Skip to content

Commit

Permalink
新增注解@MockClass
Browse files Browse the repository at this point in the history
  • Loading branch information
woilsy committed Jul 17, 2023
1 parent f16f857 commit 0a5e813
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 29 deletions.
26 changes: 7 additions & 19 deletions app/src/main/java/com/woilsy/mock/test/api/ApiService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,13 @@

import com.woilsy.mock.annotations.MockExclude;
import com.woilsy.mock.annotations.MockObj;
import com.woilsy.mock.test.entity.HttpResult;
import com.woilsy.mock.test.entity.LoginRequest;
import com.woilsy.mock.test.entity.LoginResponse;
import com.woilsy.mock.test.entity.PageBean;
import com.woilsy.mock.test.entity.RegisterRequest;
import com.woilsy.mock.test.entity.UserInfo;

import java.util.List;

import com.woilsy.mock.test.entity.*;
import io.reactivex.rxjava3.core.Observable;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.DELETE;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.PUT;
import retrofit2.http.Path;
import retrofit2.http.Query;
import retrofit2.http.Url;
import retrofit2.http.*;

import java.util.List;

@MockObj
public interface ApiService {
Expand Down Expand Up @@ -61,5 +46,8 @@ public interface ApiService {
@GET("/test/userList")
Observable<HttpResult<PageBean<UserInfo>>> getUserList();

@GET("/data/any")
Observable<HttpResult<AnyData>> getAnyData();

}

17 changes: 17 additions & 0 deletions app/src/main/java/com/woilsy/mock/test/entity/AnyData.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.woilsy.mock.test.entity

import com.woilsy.mock.annotations.MockClass

/**
* Any的场景一般为可能为多个内容中的一个,一般和某个字段的某个值形成键值对。--暂未实现
*/
class AnyData(
val type: Int,
@MockClass(Data1::class)
val data: Any,
)

data class Data1(
val age: Int,
val name: String
)
12 changes: 12 additions & 0 deletions app/src/main/java/com/woilsy/mock/test/ui/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -208,4 +208,16 @@ class MainActivity : AppCompatActivity() {
}
}

fun getObject(view: View) {
getApiService()
.anyData
.subscribe(
{
Log.d(TAG, "getObject: ${it.data}")
}, {
it.printStackTrace()
}
)
}

}
6 changes: 6 additions & 0 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@
android:text="部分接口不Mock(GET)"
android:textAllCaps="false"/>

<Button
android:layout_width="match_parent"
android:text="返回类型为Object"
android:onClick="getObject"
android:layout_height="wrap_content"/>

<TextView
android:text="动态url请求"
android:textSize="16sp"
Expand Down
17 changes: 17 additions & 0 deletions mock/src/main/java/com/woilsy/mock/annotations/MockClass.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.woilsy.mock.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 一般情况下通过字段可以自动获取其类型,但部分情况例外。如可用于字段是个Object类型的时候,显式指定其类型。
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MockClass {

Class<?> value();

}
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@ private Object generatorFinalObj(Class<?> cls, Field parentField) {
//纯粹的尝试获取Final字段 需要先判定是否为可解析类型。。。可解析时 直接返回 不可解析时返回null
if (getMockOptions().getRules() == null) return null;
try {
Object data = getMockFieldData(cls, parentField);
if (data != null) {//带mock注解,且解析出数据
return data;
if (parentField != null) {
Object data = getMockFieldData(cls, parentField.getAnnotations());
if (data != null) {//带mock注解,且解析出数据
return data;
}
}
} catch (Exception e) {
loge("()->生成final字段" + cls + "失败");
Expand Down Expand Up @@ -97,9 +99,9 @@ private boolean checkClass(Class<?> cls) {
private void handleField(Object obj, Type type, Field f) throws IllegalAccessException {
if (type instanceof Class) {
if (checkField(f)) {
Object fieldData = getMockFieldData((Class<?>) type, f);
Object fieldData = getMockFieldData((Class<?>) type, f.getAnnotations());
if (fieldData == null) {
logi("()->没有mock注解数据,使用默认方式");
logi("()->" + f.getName() + "没有mock注解数据,使用默认方式");
handleFieldType(f, obj);
} else {
logi("()->解析mock注解成功,直接赋值到字段中" + f.getName());
Expand Down Expand Up @@ -135,10 +137,13 @@ private void handleFieldType(Field field, Object parent) throws IllegalAccessExc
}
}

//只处理带Mock注解的情况,其他情况直接返回null表示没有通过该注解获取到内容
private Object getMockFieldData(Class<?> cls, Field field) {
if (field == null) return null;
Annotation[] annotations = field.getAnnotations();
/**
* 处理Mock系列注解
*
* @return 其他情况直接返回null表示没有通过该注解获取到内容
*/
private Object getMockFieldData(Class<?> cls, Annotation[] annotations) {
if (annotations == null) return null;
for (Annotation annotation : annotations) {
if (annotation instanceof Mock) {
//如果data有值 尝试将其转换为对应的值 一般是基本类型从string转为xxx等,需要匹配cls
Expand Down Expand Up @@ -170,6 +175,11 @@ private Object getMockFieldData(Class<?> cls, Field field) {
return MockRangeUtil.longRange((MockLongRange) annotation);
} else if (annotation instanceof MockStringRange) {
return MockRangeUtil.stringRange((MockStringRange) annotation);
} else if (annotation instanceof MockClass) {
Class<?> value = ((MockClass) annotation).value();
if (cls == Object.class) {
return ClassUtils.newClassInstance(value);
}
}
}
return null;
Expand Down
5 changes: 4 additions & 1 deletion mock/src/main/java/com/woilsy/mock/utils/ClassUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,17 +110,20 @@ public static <T> Object allocateInstance(Class<T> cls) {
* 通过class生成一个对象
*/
public static Object newClassInstance(Class<?> cls) {
if (cls == null) return null;
String name = cls.getSimpleName();
try {//默认构造器创建
Constructor<?>[] constructors = cls.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
int len = constructor.getParameterTypes().length;
if (len == 0) {
constructor.setAccessible(true);
LogUtil.i("已通过构造器创建->" + name);
return constructor.newInstance();
}
}
} catch (Exception e) {//使用不安全的方式创建
LogUtil.e("构造器创建失败,尝试使用Unsafe创建。");
LogUtil.e("构造器创建失败,尝试使用Unsafe创建->" + name);
}
return unsafeCreate(cls);
}
Expand Down

0 comments on commit 0a5e813

Please sign in to comment.