功能概述
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 history,用途是什么?
解答:在Pojo属性为复杂类型时,即需要递归转换或解析时,就可以把已经处理过的结果放入Map中,传递给下一个转换或解析。下次处理前,会判断是否已经处理过,处理过的就不再处理。这样已经处理过的类型就不用处理了,提升处理性能。
归纳总结
PojoUtils转换中,简单类型包含:基本类型、Number、Date、元素为基本类型的数组、集合类型等。
在类型转换时,会进行递归调用,一直解析到位简单类型为止。