All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.taobao.hsf.util.PojoUtils Maven / Gradle / Ivy

There is a newer version: 1.8.3
Show newest version
/*
 * Copyright 1999-2011 Alibaba Group.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.taobao.hsf.util;


import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListMap;

/**
 * PojoUtils. Travel object deeply, and convert complex type to simple type.
 * 

* Simple type below will be remained: *

    *
  • Primitive Type, also include String, Number(Integer, Long), Date *
  • Array of Primitive Type *
  • Collection, eg: List, Map, Set etc. *
*

* Other type will be covert to a map which contains the attributes and value pair of object. * * @author william.liangf * @author ding.lid */ public class PojoUtils { private static final ConcurrentMap, ConcurrentMap> NAME_METHODS_CACHE = new ConcurrentHashMap, ConcurrentMap>(); private static final ConcurrentMap, ConcurrentMap> CLASS_FIELD_CACHE = new ConcurrentHashMap, ConcurrentMap>(); private static boolean isUnSafeEnabled; private static sun.misc.Unsafe unsafe; private static List WARP_TYPE = new ArrayList(); static { WARP_TYPE.add(Byte.class); WARP_TYPE.add(Character.class); WARP_TYPE.add(Short.class); WARP_TYPE.add(Integer.class); WARP_TYPE.add(Float.class); WARP_TYPE.add(Double.class); WARP_TYPE.add(Long.class); } static { try { unsafe = getUnsafe(); isUnSafeEnabled = unsafe != null; } catch (Throwable e) { } } public static Object[] generalize(Object[] objs) { Object[] dests = new Object[objs.length]; for (int i = 0; i < objs.length; i++) { dests[i] = generalize(objs[i]); } return dests; } public static Object[] realize(Object[] objs, Class[] types) { if (objs.length != types.length) throw new IllegalArgumentException("args.length != types.length"); Object[] dests = new Object[objs.length]; for (int i = 0; i < objs.length; i++) { dests[i] = realize(objs[i], types[i]); } return dests; } public static Object[] realize(Object[] objs, Class[] types, Type[] gtypes) { if (objs == null) { return new Object[types.length]; } if (objs.length != types.length || objs.length != gtypes.length) throw new IllegalArgumentException("args.length != types.length"); Object[] dests = new Object[objs.length]; for (int i = 0; i < objs.length; i++) { dests[i] = realize(objs[i], types[i], gtypes[i]); } return dests; } //remove class filed from json string public static Object removeGeneralizedClassInfo(Object appResponse) { return simplifyPojo(appResponse, true, false); } //util function for user to simply pojo public static Object simplifyPojo(Object appResponse, boolean removeClass, boolean removeNull) { if (!removeClass && !removeNull) { return appResponse; } if (appResponse == null || ReflectUtils.isPrimitives(appResponse.getClass())) { return appResponse; } if (appResponse.getClass().isArray()) { int len = Array.getLength(appResponse); Object[] dest = new Object[len]; for (int i = 0; i < len; i++) { Object obj = Array.get(appResponse, i); dest[i] = simplifyPojo(obj, removeClass, removeNull); } return dest; } if (appResponse instanceof Collection) { Collection src = (Collection) appResponse; int len = src.size(); Collection dest = (appResponse instanceof List) ? new ArrayList(len) : new HashSet(len); for (Object obj : src) { dest.add(simplifyPojo(obj, removeClass, removeNull)); } return dest; } if (appResponse instanceof Map) { Map src = (Map) appResponse; Map dest = createMap(src); for (Map.Entry obj : src.entrySet()) { if (removeClass && obj.getKey().equals("class")) { continue; } if (removeNull && obj.getValue() == null) { continue; } dest.put(simplifyPojo(obj.getKey(), removeClass, removeNull), simplifyPojo(obj.getValue(), removeClass, removeNull)); } return dest; } return appResponse; } public static Object generalize(Object pojo) { return generalize(pojo, new IdentityHashMap(), false, false); } public static Object generalize(Object pojo, boolean removeClass, boolean removeNull) { return generalize(pojo, new IdentityHashMap(), removeClass, removeNull); } @SuppressWarnings("unchecked") private static Object generalize(Object pojo, Map history, boolean removeClass, boolean removeNull) { 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, removeClass, removeNull); } return dest; } if (pojo instanceof Collection) { Collection src = (Collection) pojo; int len = src.size(); Collection dest = (pojo instanceof List) ? new ArrayList(len) : new HashSet(len); history.put(pojo, dest); for (Object obj : src) { dest.add(generalize(obj, history, removeClass, removeNull)); } return dest; } if (pojo instanceof Map) { Map src = (Map) pojo; Map dest = createMap(src); history.put(pojo, dest); for (Map.Entry obj : src.entrySet()) { dest.put(generalize(obj.getKey(), history, removeClass, removeNull), generalize(obj.getValue(), history, removeClass, removeNull)); } return dest; } Map map = new HashMap(); history.put(pojo, map); if (!removeClass) { map.put("class", pojo.getClass().getName()); } for (Method method : pojo.getClass().getMethods()) { if (ReflectUtils.isBeanPropertyReadMethod(method)) { try { String propertyName = ReflectUtils.getPropertyNameFromBeanReadMethod(method); try { Field field = pojo.getClass().getDeclaredField(propertyName); if (null != field) { if (method.getName().startsWith("is") && (field.getType() != boolean.class && field.getType() != Boolean.class)) { continue; } } } catch (Exception t) { // ignore no such field exception } method.setAccessible(true); Object result = generalize(method.invoke(pojo), history, removeClass, removeNull); if (!(removeNull && result == null)) { map.put(propertyName, result); } } catch (Exception e) { if(e instanceof InvocationTargetException) { throw new RuntimeException("Pojo generalized failed!", e.getCause()); } else { throw new RuntimeException("Pojo generalized failed!", e); } } } } // public field for (Field field : pojo.getClass().getFields()) { if (ReflectUtils.isPublicInstanceField(field)) { try { Object fieldValue = field.get(pojo); // public filed同时也有get/set方法,如果get/set存取的不是前面那个 public field 该如何处理 if (history.containsKey(pojo)) { Object pojoGenerilizedValue = history.get(pojo); if (pojoGenerilizedValue instanceof Map && ((Map) pojoGenerilizedValue).containsKey(field.getName())) { continue; } } if (fieldValue != null) { Object result = generalize(fieldValue, history, removeClass, removeNull); if (!(removeNull && result == null)) { map.put(field.getName(), result); } } } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } } } return map; } public static Object realize(Object pojo, Class type) { return realize0(pojo, type, null, new IdentityHashMap()); } public static Object realize(Object pojo, Class type, Type genericType) { return realize0(pojo, type, genericType, new IdentityHashMap()); } @SuppressWarnings("unchecked") private static Collection createCollection(Class type, int len) { if (type.isAssignableFrom(ArrayList.class)) { return new ArrayList(len); } if (type.isAssignableFrom(HashSet.class)) { return new HashSet(len); } if (!type.isInterface() && !Modifier.isAbstract(type.getModifiers())) { try { return (Collection) type.newInstance(); } catch (Exception e) { // ignore } } return new ArrayList(); } @SuppressWarnings("rawtypes") private static Map createMap(Map src) { Class cl = src.getClass(); Map result = null; if (HashMap.class == cl) { result = new HashMap(); } else if (Hashtable.class == cl) { result = new Hashtable(); } else if (IdentityHashMap.class == cl) { result = new IdentityHashMap(); } else if (LinkedHashMap.class == cl) { result = new LinkedHashMap(); } else if (Properties.class == cl) { result = new Properties(); } else if (TreeMap.class == cl) { result = new TreeMap(); } else if (WeakHashMap.class == cl) { return new WeakHashMap(); } else if (ConcurrentHashMap.class == cl) { result = new ConcurrentHashMap(); } else if (ConcurrentSkipListMap.class == cl) { result = new ConcurrentSkipListMap(); } else { try { result = cl.newInstance(); } catch (Exception e) { /* ignore */ } if (result == null) { try { Constructor constructor = cl.getConstructor(Map.class); result = (Map) constructor.newInstance(Collections.EMPTY_MAP); } catch (Exception e) { /* ignore */ } } } if (result == null) { result = new HashMap(); } return result; } @SuppressWarnings({"unchecked", "rawtypes"}) private static Object realize0(Object pojo, Class type, Type genericType, final Map history) { return null; } /** * 获取范型的类型 * * @param genericType * @param index * @return List 返回Person.class ,Map index=0 返回String.class index=1 返回Person.class */ private static Type getGenericClassByIndex(Type genericType, int index) { Type clazz = null; // 范型参数转换 if (genericType instanceof ParameterizedType) { ParameterizedType t = (ParameterizedType) genericType; Type[] types = t.getActualTypeArguments(); clazz = types[index]; } return clazz; } private static Object newInstance(Class cls) { return null; } private static Method getSetterMethod(Class cls, String property, Class valueCls) { String name = "set" + property.substring(0, 1).toUpperCase() + property.substring(1); Method method = null; ConcurrentMap methods = NAME_METHODS_CACHE.get(cls); if (methods != null) { method = methods.get(name + "(" + valueCls.getName() + ")"); } else { methods = new ConcurrentHashMap(); NAME_METHODS_CACHE.put(cls, methods); } if (method == null) { try { try { method = cls.getMethod(name, valueCls); } catch (NoSuchMethodException e) { if (WARP_TYPE.contains(valueCls)) { try { Field f = valueCls.getField("TYPE"); method = cls.getMethod(name, (Class) f.get(null)); } catch (NoSuchFieldException e1) { throw e; } catch (IllegalAccessException e2) { throw e; } } else { throw e; } } } catch (NoSuchMethodException e) { List reloadMethods = new ArrayList(); for (Method m : cls.getMethods()) { if (ReflectUtils.isBeanPropertyWriteMethod(m) && m.getName().equals(name)) { reloadMethods.add(m); } } if (reloadMethods.size() != 1) { if (!WARP_TYPE.contains(valueCls)) { for (Method reload : reloadMethods) { if (!reload.getParameterTypes()[0].isPrimitive() && !WARP_TYPE.contains(reload.getParameterTypes()[0])) { method = reload; break; } } } } if (null == method && reloadMethods.size() > 0) { method = reloadMethods.get(0); } } if (method != null) { methods.putIfAbsent(name + "(" + valueCls.getName() + ")", method); } } return method; } private static Field getField(Class cls, String fieldName) { Field result = null; if (CLASS_FIELD_CACHE.containsKey(cls) && CLASS_FIELD_CACHE.get(cls).containsKey(fieldName)) { return CLASS_FIELD_CACHE.get(cls).get(fieldName); } try { result = cls.getField(fieldName); } catch (NoSuchFieldException e) { for (Field field : cls.getFields()) { if (fieldName.equals(field.getName()) && ReflectUtils.isPublicInstanceField(field)) { result = field; break; } } } // 获取私有字段 if (result == null) { for (Field field : cls.getDeclaredFields()) { if (fieldName.equals(field.getName())) { field.setAccessible(true); result = field; break; } } } if (result != null) { ConcurrentMap fields = CLASS_FIELD_CACHE.get(cls); if (fields == null) { fields = new ConcurrentHashMap(); CLASS_FIELD_CACHE.putIfAbsent(cls, fields); } fields = CLASS_FIELD_CACHE.get(cls); fields.putIfAbsent(fieldName, result); } return result; } public static boolean isPojo(Class cls) { return !ReflectUtils.isPrimitives(cls) && !Collection.class.isAssignableFrom(cls) && !Map.class.isAssignableFrom(cls); } /** * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package. Replace with a simple call to * Unsafe.getUnsafe when integrating into a jdk. * * @return a sun.misc.Unsafe */ private static sun.misc.Unsafe getUnsafe() { try { return sun.misc.Unsafe.getUnsafe(); } catch (SecurityException tryReflectionInstead) { } try { return java.security.AccessController .doPrivileged(new java.security.PrivilegedExceptionAction() { public sun.misc.Unsafe run() throws Exception { Class k = sun.misc.Unsafe.class; for (java.lang.reflect.Field f : k.getDeclaredFields()) { f.setAccessible(true); Object x = f.get(null); if (k.isInstance(x)) return k.cast(x); } throw new NoSuchFieldError("the Unsafe"); } }); } catch (java.security.PrivilegedActionException e) { throw new RuntimeException("Could not initialize intrinsics", e.getCause()); } } public static boolean isGenericBizException(Object appResponse) { //泛化调用的结果 if (!(appResponse instanceof Map)) return false; Map response = (Map) appResponse; return response.containsKey("cause") && response.containsKey("message") && response.containsKey("stackTrace"); } public static Throwable getGenericBizException(Object appResponse) { return null; } public static boolean isGenericMethod(String methodName, String[] sig) { return methodName.equals(HSFConstants.$INVOKE) && sig != null && sig.length == 3; } private static class PojoInvocationHandler implements InvocationHandler { private Map map; public PojoInvocationHandler(Map map) { this.map = map; } @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) value, method.getReturnType(), null, new IdentityHashMap()); } return value; } } }