首页

关于alibaba的dubbo源码包中PojoUtils简单对象工具类对简单对象的类映射、集合等常见处理

标签:alibaba,dubbo,PojoUtils,简单对象工具类     发布时间:2018-06-22   

一、前言

关于alibaba的dubbo源码包com.alibaba.dubbo.common.utils.PojoUtils简单对象工具类,对简单对象集合、复杂数据类型与简单数据类型转换处理、,详情参见源码说明。

二、源码说明

package com.alibaba.dubbo.common.utils;@b@@b@import java.lang.reflect.Array;@b@import java.lang.reflect.Constructor;@b@import java.lang.reflect.Field;@b@import java.lang.reflect.InvocationHandler;@b@import java.lang.reflect.InvocationTargetException;@b@import java.lang.reflect.Method;@b@import java.lang.reflect.Modifier;@b@import java.lang.reflect.ParameterizedType;@b@import java.lang.reflect.Proxy;@b@import java.lang.reflect.Type;@b@import java.util.ArrayList;@b@import java.util.Collection;@b@import java.util.Collections;@b@import java.util.HashMap;@b@import java.util.HashSet;@b@import java.util.Hashtable;@b@import java.util.IdentityHashMap;@b@import java.util.LinkedHashMap;@b@import java.util.List;@b@import java.util.Map;@b@import java.util.Properties;@b@import java.util.TreeMap;@b@import java.util.WeakHashMap;@b@import java.util.concurrent.ConcurrentHashMap;@b@import java.util.concurrent.ConcurrentMap;@b@import java.util.concurrent.ConcurrentSkipListMap;@b@@b@ @b@public class PojoUtils {@b@@b@    private static final ConcurrentMap<String, Method> NAME_METHODS_CACHE = new ConcurrentHashMap<String, Method>();@b@    private static final ConcurrentMap<Class<?>, ConcurrentMap<String, Field>> CLASS_FIELD_CACHE = new ConcurrentHashMap<Class<?>, ConcurrentMap<String, Field>>();@b@@b@    public static Object[] generalize(Object[] objs) {@b@        Object[] dests = new Object[objs.length];@b@        for (int i = 0; i < objs.length; i++) {@b@            dests[i] = generalize(objs[i]);@b@        }@b@        return dests;@b@    }@b@@b@    public static Object[] realize(Object[] objs, Class<?>[] types) {@b@        if (objs.length != types.length)@b@            throw new IllegalArgumentException("args.length != types.length");@b@        Object[] dests = new Object[objs.length];@b@        for (int i = 0; i < objs.length; i++) {@b@            dests[i] = realize(objs[i], types[i]);@b@        }@b@        return dests;@b@    }@b@@b@    public static Object[] realize(Object[] objs, Class<?>[] types, Type[] gtypes) {@b@        if (objs.length != types.length || objs.length != gtypes.length)@b@            throw new IllegalArgumentException("args.length != types.length");@b@        Object[] dests = new Object[objs.length];@b@        for (int i = 0; i < objs.length; i++) {@b@            dests[i] = realize(objs[i], types[i], gtypes[i]);@b@        }@b@        return dests;@b@    }@b@@b@    public static Object generalize(Object pojo) {@b@        return generalize(pojo, new IdentityHashMap<Object, Object>());@b@    }@b@@b@    @SuppressWarnings("unchecked")@b@    private static Object generalize(Object pojo, Map<Object, Object> history) {@b@        if (pojo == null) {@b@            return null;@b@        }@b@@b@        if (pojo instanceof Enum<?>) {@b@            return ((Enum<?>) pojo).name();@b@        }@b@        if (pojo.getClass().isArray() && Enum.class.isAssignableFrom(pojo.getClass().getComponentType())) {@b@            int len = Array.getLength(pojo);@b@            String[] values = new String[len];@b@            for (int i = 0; i < len; i++) {@b@                values[i] = ((Enum<?>) Array.get(pojo, i)).name();@b@            }@b@            return values;@b@        }@b@@b@        if (ReflectUtils.isPrimitives(pojo.getClass())) {@b@            return pojo;@b@        }@b@@b@        if (pojo instanceof Class) {@b@            return ((Class) pojo).getName();@b@        }@b@@b@        Object o = history.get(pojo);@b@        if (o != null) {@b@            return o;@b@        }@b@        history.put(pojo, pojo);@b@@b@        if (pojo.getClass().isArray()) {@b@            int len = Array.getLength(pojo);@b@            Object[] dest = new Object[len];@b@            history.put(pojo, dest);@b@            for (int i = 0; i < len; i++) {@b@                Object obj = Array.get(pojo, i);@b@                dest[i] = generalize(obj, history);@b@            }@b@            return dest;@b@        }@b@        if (pojo instanceof Collection<?>) {@b@            Collection<Object> src = (Collection<Object>) pojo;@b@            int len = src.size();@b@            Collection<Object> dest = (pojo instanceof List<?>) ? new ArrayList<Object>(len) : new HashSet<Object>(len);@b@            history.put(pojo, dest);@b@            for (Object obj : src) {@b@                dest.add(generalize(obj, history));@b@            }@b@            return dest;@b@        }@b@        if (pojo instanceof Map<?, ?>) {@b@            Map<Object, Object> src = (Map<Object, Object>) pojo;@b@            Map<Object, Object> dest = createMap(src);@b@            history.put(pojo, dest);@b@            for (Map.Entry<Object, Object> obj : src.entrySet()) {@b@                dest.put(generalize(obj.getKey(), history), generalize(obj.getValue(), history));@b@            }@b@            return dest;@b@        }@b@        Map<String, Object> map = new HashMap<String, Object>();@b@        history.put(pojo, map);@b@        map.put("class", pojo.getClass().getName());@b@        for (Method method : pojo.getClass().getMethods()) {@b@            if (ReflectUtils.isBeanPropertyReadMethod(method)) {@b@                try {@b@                    map.put(ReflectUtils.getPropertyNameFromBeanReadMethod(method), generalize(method.invoke(pojo), history));@b@                } catch (Exception e) {@b@                    throw new RuntimeException(e.getMessage(), e);@b@                }@b@            }@b@        }@b@        // public field@b@        for (Field field : pojo.getClass().getFields()) {@b@            if (ReflectUtils.isPublicInstanceField(field)) {@b@                try {@b@                    Object fieldValue = field.get(pojo);@b@                    if (history.containsKey(pojo)) {@b@                        Object pojoGenerilizedValue = history.get(pojo);@b@                        if (pojoGenerilizedValue instanceof Map@b@                                && ((Map) pojoGenerilizedValue).containsKey(field.getName())) {@b@                            continue;@b@                        }@b@                    }@b@                    if (fieldValue != null) {@b@                        map.put(field.getName(), generalize(fieldValue, history));@b@                    }@b@                } catch (Exception e) {@b@                    throw new RuntimeException(e.getMessage(), e);@b@                }@b@            }@b@        }@b@        return map;@b@    }@b@@b@    public static Object realize(Object pojo, Class<?> type) {@b@        return realize0(pojo, type, null, new IdentityHashMap<Object, Object>());@b@    }@b@@b@    public static Object realize(Object pojo, Class<?> type, Type genericType) {@b@        return realize0(pojo, type, genericType, new IdentityHashMap<Object, Object>());@b@    }@b@@b@    private static class PojoInvocationHandler implements InvocationHandler {@b@@b@        private Map<Object, Object> map;@b@@b@        public PojoInvocationHandler(Map<Object, Object> map) {@b@            this.map = map;@b@        }@b@@b@        @SuppressWarnings("unchecked")@b@        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {@b@            if (method.getDeclaringClass() == Object.class) {@b@                return method.invoke(map, args);@b@            }@b@            String methodName = method.getName();@b@            Object value = null;@b@            if (methodName.length() > 3 && methodName.startsWith("get")) {@b@                value = map.get(methodName.substring(3, 4).toLowerCase() + methodName.substring(4));@b@            } else if (methodName.length() > 2 && methodName.startsWith("is")) {@b@                value = map.get(methodName.substring(2, 3).toLowerCase() + methodName.substring(3));@b@            } else {@b@                value = map.get(methodName.substring(0, 1).toLowerCase() + methodName.substring(1));@b@            }@b@            if (value instanceof Map<?, ?> && !Map.class.isAssignableFrom(method.getReturnType())) {@b@                value = realize0((Map<String, Object>) value, method.getReturnType(), null, new IdentityHashMap<Object, Object>());@b@            }@b@            return value;@b@        }@b@    }@b@@b@    @SuppressWarnings("unchecked")@b@    private static Collection<Object> createCollection(Class<?> type, int len) {@b@        if (type.isAssignableFrom(ArrayList.class)) {@b@            return new ArrayList<Object>(len);@b@        }@b@        if (type.isAssignableFrom(HashSet.class)) {@b@            return new HashSet<Object>(len);@b@        }@b@        if (!type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {@b@            try {@b@                return (Collection<Object>) type.newInstance();@b@            } catch (Exception e) {@b@                // ignore@b@            }@b@        }@b@        return new ArrayList<Object>();@b@    }@b@@b@    private static Map createMap(Map src) {@b@        Class<? extends Map> cl = src.getClass();@b@        Map result = null;@b@        if (HashMap.class == cl) {@b@            result = new HashMap();@b@        } else if (Hashtable.class == cl) {@b@            result = new Hashtable();@b@        } else if (IdentityHashMap.class == cl) {@b@            result = new IdentityHashMap();@b@        } else if (LinkedHashMap.class == cl) {@b@            result = new LinkedHashMap();@b@        } else if (Properties.class == cl) {@b@            result = new Properties();@b@        } else if (TreeMap.class == cl) {@b@            result = new TreeMap();@b@        } else if (WeakHashMap.class == cl) {@b@            return new WeakHashMap();@b@        } else if (ConcurrentHashMap.class == cl) {@b@            result = new ConcurrentHashMap();@b@        } else if (ConcurrentSkipListMap.class == cl) {@b@            result = new ConcurrentSkipListMap();@b@        } else {@b@            try {@b@                result = cl.newInstance();@b@            } catch (Exception e) { /* ignore */ }@b@@b@            if (result == null) {@b@                try {@b@                    Constructor<?> constructor = cl.getConstructor(Map.class);@b@                    result = (Map) constructor.newInstance(Collections.EMPTY_MAP);@b@                } catch (Exception e) { /* ignore */ }@b@            }@b@        }@b@@b@        if (result == null) {@b@            result = new HashMap<Object, Object>();@b@        }@b@@b@        return result;@b@    }@b@@b@    @SuppressWarnings({"unchecked", "rawtypes"})@b@    private static Object realize0(Object pojo, Class<?> type, Type genericType, final Map<Object, Object> history) {@b@        if (pojo == null) {@b@            return null;@b@        }@b@@b@        if (type != null && type.isEnum() && pojo.getClass() == String.class) {@b@            return Enum.valueOf((Class<Enum>) type, (String) pojo);@b@        }@b@@b@        if (ReflectUtils.isPrimitives(pojo.getClass())@b@                && !(type != null && type.isArray()@b@                && type.getComponentType().isEnum()@b@                && pojo.getClass() == String[].class)) {@b@            return CompatibleTypeUtils.compatibleTypeConvert(pojo, type);@b@        }@b@@b@        Object o = history.get(pojo);@b@@b@        if (o != null) {@b@            return o;@b@        }@b@@b@        history.put(pojo, pojo);@b@@b@        if (pojo.getClass().isArray()) {@b@            if (Collection.class.isAssignableFrom(type)) {@b@                Class<?> ctype = pojo.getClass().getComponentType();@b@                int len = Array.getLength(pojo);@b@                Collection dest = createCollection(type, len);@b@                history.put(pojo, dest);@b@                for (int i = 0; i < len; i++) {@b@                    Object obj = Array.get(pojo, i);@b@                    Object value = realize0(obj, ctype, null, history);@b@                    dest.add(value);@b@                }@b@                return dest;@b@            } else {@b@                Class<?> ctype = (type != null && type.isArray() ? type.getComponentType() : pojo.getClass().getComponentType());@b@                int len = Array.getLength(pojo);@b@                Object dest = Array.newInstance(ctype, len);@b@                history.put(pojo, dest);@b@                for (int i = 0; i < len; i++) {@b@                    Object obj = Array.get(pojo, i);@b@                    Object value = realize0(obj, ctype, null, history);@b@                    Array.set(dest, i, value);@b@                }@b@                return dest;@b@            }@b@        }@b@@b@        if (pojo instanceof Collection<?>) {@b@            if (type.isArray()) {@b@                Class<?> ctype = type.getComponentType();@b@                Collection<Object> src = (Collection<Object>) pojo;@b@                int len = src.size();@b@                Object dest = Array.newInstance(ctype, len);@b@                history.put(pojo, dest);@b@                int i = 0;@b@                for (Object obj : src) {@b@                    Object value = realize0(obj, ctype, null, history);@b@                    Array.set(dest, i, value);@b@                    i++;@b@                }@b@                return dest;@b@            } else {@b@                Collection<Object> src = (Collection<Object>) pojo;@b@                int len = src.size();@b@                Collection<Object> dest = createCollection(type, len);@b@                history.put(pojo, dest);@b@                for (Object obj : src) {@b@                    Type keyType = getGenericClassByIndex(genericType, 0);@b@                    Class<?> keyClazz = obj.getClass();@b@                    if (keyType instanceof Class) {@b@                        keyClazz = (Class<?>) keyType;@b@                    }@b@                    Object value = realize0(obj, keyClazz, keyType, history);@b@                    dest.add(value);@b@                }@b@                return dest;@b@            }@b@        }@b@@b@        if (pojo instanceof Map<?, ?> && type != null) {@b@            Object className = ((Map<Object, Object>) pojo).get("class");@b@            if (className instanceof String) {@b@                try {@b@                    type = ClassHelper.forName((String) className);@b@                } catch (ClassNotFoundException e) {@b@                    // ignore@b@                }@b@            }@b@@b@            // special logic for enum@b@            if (type.isEnum()) {@b@                Object name = ((Map<Object, Object>) pojo).get("name");@b@                if (name != null) {@b@                    return Enum.valueOf((Class<Enum>) type, name.toString());@b@                }@b@            }@b@            Map<Object, Object> map;@b@            // when return type is not the subclass of return type from the signature and not an interface@b@            if (!type.isInterface() && !type.isAssignableFrom(pojo.getClass())) {@b@                try {@b@                    map = (Map<Object, Object>) type.newInstance();@b@                    Map<Object, Object> mapPojo = (Map<Object, Object>) pojo;@b@                    map.putAll(mapPojo);@b@                    map.remove("class");@b@                } catch (Exception e) {@b@                    //ignore error@b@                    map = (Map<Object, Object>) pojo;@b@                }@b@            } else {@b@                map = (Map<Object, Object>) pojo;@b@            }@b@@b@            if (Map.class.isAssignableFrom(type) || type == Object.class) {@b@                final Map<Object, Object> result = createMap(map);@b@                history.put(pojo, result);@b@                for (Map.Entry<Object, Object> entry : map.entrySet()) {@b@                    Type keyType = getGenericClassByIndex(genericType, 0);@b@                    Type valueType = getGenericClassByIndex(genericType, 1);@b@                    Class<?> keyClazz;@b@                    if (keyType instanceof Class) {@b@                        keyClazz = (Class<?>) keyType;@b@                    } else if (keyType instanceof ParameterizedType) {@b@                        keyClazz = (Class<?>) ((ParameterizedType) keyType).getRawType();@b@                    } else {@b@                        keyClazz = entry.getKey() == null ? null : entry.getKey().getClass();@b@                    }@b@                    Class<?> valueClazz;@b@                    if (valueType instanceof Class) {@b@                        valueClazz = (Class<?>) valueType;@b@                    } else if (valueType instanceof ParameterizedType) {@b@                        valueClazz = (Class<?>) ((ParameterizedType) valueType).getRawType();@b@                    } else {@b@                        valueClazz = entry.getValue() == null ? null : entry.getValue().getClass();@b@                    }@b@@b@                    Object key = keyClazz == null ? entry.getKey() : realize0(entry.getKey(), keyClazz, keyType, history);@b@                    Object value = valueClazz == null ? entry.getValue() : realize0(entry.getValue(), valueClazz, valueType, history);@b@                    result.put(key, value);@b@                }@b@                return result;@b@            } else if (type.isInterface()) {@b@                Object dest = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[]{type}, new PojoInvocationHandler(map));@b@                history.put(pojo, dest);@b@                return dest;@b@            } else {@b@                Object dest = newInstance(type);@b@                history.put(pojo, dest);@b@                for (Map.Entry<Object, Object> entry : map.entrySet()) {@b@                    Object key = entry.getKey();@b@                    if (key instanceof String) {@b@                        String name = (String) key;@b@                        Object value = entry.getValue();@b@                        if (value != null) {@b@                            Method method = getSetterMethod(dest.getClass(), name, value.getClass());@b@                            Field field = getField(dest.getClass(), name);@b@                            if (method != null) {@b@                                if (!method.isAccessible())@b@                                    method.setAccessible(true);@b@                                Type ptype = method.getGenericParameterTypes()[0];@b@                                value = realize0(value, method.getParameterTypes()[0], ptype, history);@b@                                try {@b@                                    method.invoke(dest, value);@b@                                } catch (Exception e) {@b@                                    e.printStackTrace();@b@                                    throw new RuntimeException("Failed to set pojo " + dest.getClass().getSimpleName() + " property " + name@b@                                            + " value " + value + "(" + value.getClass() + "), cause: " + e.getMessage(), e);@b@                                }@b@                            } else if (field != null) {@b@                                value = realize0(value, field.getType(), field.getGenericType(), history);@b@                                try {@b@                                    field.set(dest, value);@b@                                } catch (IllegalAccessException e) {@b@                                    throw new RuntimeException("Failed to set filed " + name + " of pojo " + dest.getClass().getName() + " : " + e.getMessage(), e);@b@                                }@b@                            }@b@                        }@b@                    }@b@                }@b@                if (dest instanceof Throwable) {@b@                    Object message = map.get("message");@b@                    if (message instanceof String) {@b@                        try {@b@                            Field filed = Throwable.class.getDeclaredField("detailMessage");@b@                            if (!filed.isAccessible()) {@b@                                filed.setAccessible(true);@b@                            }@b@                            filed.set(dest, message);@b@                        } catch (Exception e) {@b@                        }@b@                    }@b@                }@b@                return dest;@b@            }@b@        }@b@        return pojo;@b@    }@b@@b@    /**@b@     * Get parameterized type@b@     *@b@     * @param genericType generic type@b@     * @param index       index of the target parameterized type@b@     * @return Return Person.class for List<Person>, return Person.class for Map<String, Person> when index=0@b@     */@b@    private static Type getGenericClassByIndex(Type genericType, int index) {@b@        Type clazz = null;@b@        // find parameterized type@b@        if (genericType instanceof ParameterizedType) {@b@            ParameterizedType t = (ParameterizedType) genericType;@b@            Type[] types = t.getActualTypeArguments();@b@            clazz = types[index];@b@        }@b@        return clazz;@b@    }@b@@b@    private static Object newInstance(Class<?> cls) {@b@        try {@b@            return cls.newInstance();@b@        } catch (Throwable t) {@b@            try {@b@                Constructor<?>[] constructors = cls.getDeclaredConstructors();@b@                if (constructors != null && constructors.length == 0) {@b@                    throw new RuntimeException("Illegal constructor: " + cls.getName());@b@                }@b@                Constructor<?> constructor = constructors[0];@b@                if (constructor.getParameterTypes().length > 0) {@b@                    for (Constructor<?> c : constructors) {@b@                        if (c.getParameterTypes().length < constructor.getParameterTypes().length) {@b@                            constructor = c;@b@                            if (constructor.getParameterTypes().length == 0) {@b@                                break;@b@                            }@b@                        }@b@                    }@b@                }@b@                constructor.setAccessible(true);@b@                return constructor.newInstance(new Object[constructor.getParameterTypes().length]);@b@            } catch (InstantiationException e) {@b@                throw new RuntimeException(e.getMessage(), e);@b@            } catch (IllegalAccessException e) {@b@                throw new RuntimeException(e.getMessage(), e);@b@            } catch (InvocationTargetException e) {@b@                throw new RuntimeException(e.getMessage(), e);@b@            }@b@        }@b@    }@b@@b@    private static Method getSetterMethod(Class<?> cls, String property, Class<?> valueCls) {@b@        String name = "set" + property.substring(0, 1).toUpperCase() + property.substring(1);@b@        Method method = NAME_METHODS_CACHE.get(cls.getName() + "." + name + "(" + valueCls.getName() + ")");@b@        if (method == null) {@b@            try {@b@                method = cls.getMethod(name, valueCls);@b@            } catch (NoSuchMethodException e) {@b@                for (Method m : cls.getMethods()) {@b@                    if (ReflectUtils.isBeanPropertyWriteMethod(m) && m.getName().equals(name)) {@b@                        method = m;@b@                    }@b@                }@b@            }@b@            if (method != null) {@b@                NAME_METHODS_CACHE.put(cls.getName() + "." + name + "(" + valueCls.getName() + ")", method);@b@            }@b@        }@b@        return method;@b@    }@b@@b@    private static Field getField(Class<?> cls, String fieldName) {@b@        Field result = null;@b@        if (CLASS_FIELD_CACHE.containsKey(cls) && CLASS_FIELD_CACHE.get(cls).containsKey(fieldName)) {@b@            return CLASS_FIELD_CACHE.get(cls).get(fieldName);@b@        }@b@        try {@b@            result = cls.getDeclaredField(fieldName);@b@            result.setAccessible(true);@b@        } catch (NoSuchFieldException e) {@b@            for (Field field : cls.getFields()) {@b@                if (fieldName.equals(field.getName()) && ReflectUtils.isPublicInstanceField(field)) {@b@                    result = field;@b@                    break;@b@                }@b@            }@b@        }@b@        if (result != null) {@b@            ConcurrentMap<String, Field> fields = CLASS_FIELD_CACHE.get(cls);@b@            if (fields == null) {@b@                fields = new ConcurrentHashMap<String, Field>();@b@                CLASS_FIELD_CACHE.putIfAbsent(cls, fields);@b@            }@b@            fields = CLASS_FIELD_CACHE.get(cls);@b@            fields.putIfAbsent(fieldName, result);@b@        }@b@        return result;@b@    }@b@@b@    public static boolean isPojo(Class<?> cls) {@b@        return !ReflectUtils.isPrimitives(cls)@b@                && !Collection.class.isAssignableFrom(cls)@b@                && !Map.class.isAssignableFrom(cls);@b@    }@b@@b@}