org.test4j.mock.props.FakeProperties Maven / Gradle / Ivy
package org.test4j.mock.props;
import org.test4j.Logger;
import org.test4j.mock.Stubs;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
/**
* 将对象属性设置为stub对象
*
* @author wudarui
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public class FakeProperties {
private final Object target;
private final Class klass;
public FakeProperties(Object target) {
if (target == null) {
throw new RuntimeException("The target object can't be null.");
}
this.target = target;
this.klass = target.getClass();
}
/**
* 对所有空属性进行赋值, 包括父类定义的字段
*
* @return 被设置的属性对象列表
*/
public Map fakeNullProperties() {
return this.fakeProperties(f -> f.get(target) == null);
}
/**
* 只对定义了对应Annotation注解的空属性stub操作
*
* @param annotationClass 注解类列表
* @return 被设置的属性对象列表
*/
public Map fakeNullByAnnotation(Class extends Annotation>... annotationClass) {
return this.fakeProperties(f -> {
if (f.get(target) != null) {
return false;
}
for (Class extends Annotation> aClass : annotationClass) {
if (f.getAnnotation(aClass) != null) {
return true;
}
}
return false;
});
}
/**
* 对符合条件的field进行stub赋值
*
* @param predicate Predicate
*/
private Map fakeProperties(FieldPredicate predicate) {
Class aClass = this.klass;
Map properties = new HashMap<>();
while (aClass != Object.class) {
Field[] fields = aClass.getDeclaredFields();
for (Field field : fields) {
String fn = field.getName();
Class ft = field.getType();
String ftn = ft.getName();
if (fn.contains("$") ||
ft.isArray() ||
Enum.class.isAssignableFrom(ft) ||
Annotation.class.isAssignableFrom(ft) ||
ftn.startsWith("java.") ||
ftn.startsWith("sun.")) {
continue;
}
Object obj = this.fakeField(field, predicate);
if (obj != null && !aClass.isInterface()) {
properties.put(aClass.getName().replace('$', '_') + "#" + field.getName(), obj);
}
}
aClass = aClass.getSuperclass();
}
return properties;
}
/**
* 对符合条件的field进行stub赋值
*
* @param field 字段
* @param predicate 判断
* @return 返回设置的字段值(stub对象), 或者null(未设置)
*/
private Object fakeField(Field field, FieldPredicate predicate) {
boolean accessible = field.isAccessible();
try {
field.setAccessible(true);
if (!predicate.test(field)) {
return null;
}
Class aClass = field.getType();
if (aClass.isPrimitive()) {
return null;
}
Object obj;
if (Modifier.isFinal(aClass.getModifiers())) {
Constructor constructor = aClass.getDeclaredConstructor();
constructor.setAccessible(true);
obj = constructor.newInstance();
} else {
obj = Stubs.fake(field.getType());
}
if (obj != null) {
field.set(target, obj);
}
return obj;
} catch (Exception e) {
Logger.warn("fakeField[" + field.getType().getName() + "#" + field.getName() + "] error: " + e.getMessage());
} finally {
field.setAccessible(accessible);
}
return null;
}
private interface FieldPredicate {
boolean test(Field field) throws Exception;
}
}