功能概述
- PojoUtils是一个工具类,能够进行深度遍历,将简单类型与复杂类型的对象进行转换,在泛化调用时用到(在泛化调用中,主要将Pojo对象与Map对象进行相互转换)
功能分析
核心类PojoUtils分析
主要成员变量分析
private static final ConcurrentMap<String, Method> NAME_METHODS_CACHE = new ConcurrentHashMap<String, Method>();
private static final ConcurrentMap<Class<?>, ConcurrentMap<String, Field>> CLASS_FIELD_CACHE = new ConcurrentHashMap<Class<?>, ConcurrentMap<String, Field>>();
主要成员方法分析
generalize将复杂对象转换为简单对象
private static Object generalize(Object pojo, Map<Object, Object> history) {
if (pojo == null) {
return null;
}
if (pojo instanceof Enum<?>) {
return ((Enum<?>) pojo).name();
}
if (pojo.getClass().isArray() && Enum.class.isAssignableFrom(pojo.getClass().getComponentType())) {
int len = Array.getLength(pojo);
String[] values = new String[len];
for (int i = 0; i < len; i++) {
values[i] = ((Enum<?>) Array.get(pojo, i)).name();
}
return values;
}
if (ReflectUtils.isPrimitives(pojo.getClass())) {
return pojo;
}
if (pojo instanceof Class) {
return ((Class) pojo).getName();
}
Object o = history.get(pojo);
if (o != null) {
return o;
}
history.put(pojo, pojo);
if (pojo.getClass().isArray()) {
int len = Array.getLength(pojo);
Object[] dest = new Object[len];
history.put(pojo, dest);
for (int i = 0; i < len; i++) {
Object obj = Array.get(pojo, i);
dest[i] = generalize(obj, history);
}
return dest;
}
if (pojo instanceof Collection<?>) {
Collection<Object> src = (Collection<Object>) pojo;
int len = src.size();
Collection<Object> dest = (pojo instanceof List<?>) ? new ArrayList<Object>(len) : new HashSet<Object>(len);
history.put(pojo, dest);
for (Object obj : src) {
dest.add(generalize(obj, history));
}
return dest;
}
if (pojo instanceof Map<?, ?>) {
Map<Object, Object> src = (Map<Object, Object>) pojo;
Map<Object, Object> dest = createMap(src);
history.put(pojo, dest);
for (Map.Entry<Object, Object> obj : src.entrySet()) {
dest.put(generalize(obj.getKey(), history), generalize(obj.getValue(), history));
}
return dest;
}
Map<String, Object> map = new HashMap<String, Object>();
history.put(pojo, map);
if (GENERIC_WITH_CLZ) {
map.put("class", pojo.getClass().getName());
}
for (Method method : pojo.getClass().getMethods()) {
if (ReflectUtils.isBeanPropertyReadMethod(method)) {
try {
map.put(ReflectUtils.getPropertyNameFromBeanReadMethod(method), generalize(method.invoke(pojo), history));
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
for (Field field : pojo.getClass().getFields()) {
if (ReflectUtils.isPublicInstanceField(field)) {
try {
Object fieldValue = field.get(pojo);
if (history.containsKey(pojo)) {
Object pojoGeneralizedValue = history.get(pojo);
if (pojoGeneralizedValue instanceof Map
&& ((Map) pojoGeneralizedValue).containsKey(field.getName())) {
continue;
}
}
if (fieldValue != null) {
map.put(field.getName(), generalize(fieldValue, history));
}
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
return map;
}
- 代码分析:generalize方法的作用是把复杂类型对象转换为简单类型的对象,如将Pojo对象转换为Map对象,Pojo对象的成员对象若还是复杂类型,会递归调用进行转换。
realize将简单对象转换为复杂对象
private static Object realize0(Object pojo, Class<?> type, Type genericType, final Map<Object, Object> history) {
if (pojo == null) {
return null;
}
if (type != null && type.isEnum() && pojo.getClass() == String.class) {
return Enum.valueOf((Class<Enum>) type, (String) pojo);
}
if (ReflectUtils.isPrimitives(pojo.getClass())
&& !(type != null && type.isArray()
&& type.getComponentType().isEnum()
&& pojo.getClass() == String[].class)) {
return CompatibleTypeUtils.compatibleTypeConvert(pojo, type);
}
Object o = history.get(pojo);
if (o != null) {
return o;
}
history.put(pojo, pojo);
if (pojo.getClass().isArray()) {
if (Collection.class.isAssignableFrom(type)) {
Class<?> ctype = pojo.getClass().getComponentType();
int len = Array.getLength(pojo);
Collection dest = createCollection(type, len);
history.put(pojo, dest);
for (int i = 0; i < len; i++) {
Object obj = Array.get(pojo, i);
Object value = realize0(obj, ctype, null, history);
dest.add(value);
}
return dest;
} else {
Class<?> ctype = (type != null && type.isArray() ? type.getComponentType() : pojo.getClass().getComponentType());
int len = Array.getLength(pojo);
Object dest = Array.newInstance(ctype, len);
history.put(pojo, dest);
for (int i = 0; i < len; i++) {
Object obj = Array.get(pojo, i);
Object value = realize0(obj, ctype, null, history);
Array.set(dest, i, value);
}
return dest;
}
}
if (pojo instanceof Collection<?>) {
if (type.isArray()) {
Class<?> ctype = type.getComponentType();
Collection<Object> src = (Collection<Object>) pojo;
int len = src.size();
Object dest = Array.newInstance(ctype, len);
history.put(pojo, dest);
int i = 0;
for (Object obj : src) {
Object value = realize0(obj, ctype, null, history);
Array.set(dest, i, value);
i++;
}
return dest;
} else {
Collection<Object> src = (Collection<Object>) pojo;
int len = src.size();
Collection<Object> dest = createCollection(type, len);
history.put(pojo, dest);
for (Object obj : src) {
Type keyType = getGenericClassByIndex(genericType, 0);
Class<?> keyClazz = obj == null ? null : obj.getClass();
if (keyType instanceof Class) {
keyClazz = (Class<?>) keyType;
}
Object value = realize0(obj, keyClazz, keyType, history);
dest.add(value);
}
return dest;
}
}
if (pojo instanceof Map<?, ?> && type != null) {
Object className = ((Map<Object, Object>) pojo).get("class");
if (className instanceof String) {
try {
type = ClassUtils.forName((String) className);
} catch (ClassNotFoundException e) {
}
}
if (type.isEnum()) {
Object name = ((Map<Object, Object>) pojo).get("name");
if (name != null) {
return Enum.valueOf((Class<Enum>) type, name.toString());
}
}
Map<Object, Object> map;
if (!type.isInterface() && !type.isAssignableFrom(pojo.getClass())) {
try {
map = (Map<Object, Object>) type.newInstance();
Map<Object, Object> mapPojo = (Map<Object, Object>) pojo;
map.putAll(mapPojo);
if (GENERIC_WITH_CLZ) {
map.remove("class");
}
} catch (Exception e) {
map = (Map<Object, Object>) pojo;
}
} else {
map = (Map<Object, Object>) pojo;
}
if (Map.class.isAssignableFrom(type) || type == Object.class) {
final Map<Object, Object> result;
Type mapKeyType = getKeyTypeForMap(map.getClass());
Type typeKeyType = getGenericClassByIndex(genericType, 0);
boolean typeMismatch = mapKeyType instanceof Class
&& typeKeyType instanceof Class
&& !typeKeyType.getTypeName().equals(mapKeyType.getTypeName());
if (typeMismatch) {
result = createMap(new HashMap(0));
} else {
result = createMap(map);
}
history.put(pojo, result);
for (Map.Entry<Object, Object> entry : map.entrySet()) {
Type keyType = getGenericClassByIndex(genericType, 0);
Type valueType = getGenericClassByIndex(genericType, 1);
Class<?> keyClazz;
if (keyType instanceof Class) {
keyClazz = (Class<?>) keyType;
} else if (keyType instanceof ParameterizedType) {
keyClazz = (Class<?>) ((ParameterizedType) keyType).getRawType();
} else {
keyClazz = entry.getKey() == null ? null : entry.getKey().getClass();
}
Class<?> valueClazz;
if (valueType instanceof Class) {
valueClazz = (Class<?>) valueType;
} else if (valueType instanceof ParameterizedType) {
valueClazz = (Class<?>) ((ParameterizedType) valueType).getRawType();
} else {
valueClazz = entry.getValue() == null ? null : entry.getValue().getClass();
}
Object key = keyClazz == null ? entry.getKey() : realize0(entry.getKey(), keyClazz, keyType, history);
Object value = valueClazz == null ? entry.getValue() : realize0(entry.getValue(), valueClazz, valueType, history);
result.put(key, value);
}
return result;
} else if (type.isInterface()) {
Object dest = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[] {type}, new PojoInvocationHandler(map));
history.put(pojo, dest);
return dest;
} else {
Object dest = newInstance(type);
history.put(pojo, dest);
for (Map.Entry<Object, Object> entry : map.entrySet()) {
Object key = entry.getKey();
if (key instanceof String) {
String name = (String) key;
Object value = entry.getValue();
if (value != null) {
Method method = getSetterMethod(dest.getClass(), name, value.getClass());
Field field = getField(dest.getClass(), name);
if (method != null) {
if (!method.isAccessible()) {
method.setAccessible(true);
}
Type ptype = method.getGenericParameterTypes()[0];
value = realize0(value, method.getParameterTypes()[0], ptype, history);
try {
method.invoke(dest, value);
} catch (Exception e) {
String exceptionDescription = "Failed to set pojo " + dest.getClass().getSimpleName() + " property " + name
+ " value " + value + "(" + value.getClass() + "), cause: " + e.getMessage();
logger.error(exceptionDescription, e);
throw new RuntimeException(exceptionDescription, e);
}
} else if (field != null) {
value = realize0(value, field.getType(), field.getGenericType(), history);
try {
field.set(dest, value);
} catch (IllegalAccessException e) {
throw new RuntimeException("Failed to set field " + name + " of pojo " + dest.getClass().getName() + " : " + e.getMessage(), e);
}
}
}
}
}
if (dest instanceof Throwable) {
Object message = map.get("message");
if (message instanceof String) {
try {
Field field = Throwable.class.getDeclaredField("detailMessage");
if (!field.isAccessible()) {
field.setAccessible(true);
}
field.set(dest, message);
} catch (Exception e) {
}
}
}
return dest;
}
}
return pojo;
}
关联类PojoInvocationHandler分析
类中核心代码分析
private static class PojoInvocationHandler implements InvocationHandler {
private Map<Object, Object> map;
public PojoInvocationHandler(Map<Object, Object> map) {
this.map = map;
}
@Override
@SuppressWarnings("unchecked")
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(map, args);
}
String methodName = method.getName();
Object value = null;
if (methodName.length() > 3 && methodName.startsWith("get")) {
value = map.get(methodName.substring(3, 4).toLowerCase() + methodName.substring(4));
} else if (methodName.length() > 2 && methodName.startsWith("is")) {
value = map.get(methodName.substring(2, 3).toLowerCase() + methodName.substring(3));
} else {
value = map.get(methodName.substring(0, 1).toLowerCase() + methodName.substring(1));
}
if (value instanceof Map<?, ?> && !Map.class.isAssignableFrom(method.getReturnType())) {
value = realize0((Map<String, Object>) value, method.getReturnType(), null, new IdentityHashMap<Object, Object>());
}
return value;
}
}
- 代码分析:在转换的目标类型为接口时type.isInterface(),使用jdk动态代理创建接口的代理对象,PojoInvocationHandler为代理对象的调用处理器,包含了提取属性的逻辑
问题点答疑
- 在realize、generalize方法中都包含了参数Map<Object, Object> history,用途是什么?
- 解答:在Pojo属性为复杂类型时,即需要递归转换或解析时,就可以把已经处理过的结果放入Map中,传递给下一个转换或解析。下次处理前,会判断是否已经处理过,处理过的就不再处理。这样已经处理过的类型就不用处理了,提升处理性能。
归纳总结
- PojoUtils转换中,简单类型包含:基本类型、Number、Date、元素为基本类型的数组、集合类型等。
- 在类型转换时,会进行递归调用,一直解析到位简单类型为止。