/* * Copyright 2009-2016 Weibo, Inc. * * 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.weibo.api.motan.util; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; /** * 反射相关的辅助类 * * @author maijunsheng * @version 创建时间:2013-5-23 * */ public class ReflectUtil { public static final String PARAM_CLASS_SPLIT = ","; public static final String EMPTY_PARAM = "void"; private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0]; private static final ConcurrentMap<String, Class<?>> name2ClassCache = new ConcurrentHashMap<String, Class<?>>(); private static final ConcurrentMap<Class<?>, String> class2NameCache = new ConcurrentHashMap<Class<?>, String>(); private static final String[] PRIMITIVE_NAMES = new String[] {"boolean", "byte", "char", "double", "float", "int", "long", "short", "void"}; private static final Class<?>[] PRIMITIVE_CLASSES = new Class[] {boolean.class, byte.class, char.class, double.class, float.class, int.class, long.class, short.class, Void.TYPE}; private static final int PRIMITIVE_CLASS_NAME_MAX_LENGTH = 7; /** * 获取method方式的接口参数,以逗号分割,拼接clz列表。 如果没有参数,那么void表示 * * @param method * @return */ public static String getMethodParamDesc(Method method) { if (method.getParameterTypes() == null || method.getParameterTypes().length == 0) { return EMPTY_PARAM; } StringBuilder builder = new StringBuilder(); Class<?>[] clzs = method.getParameterTypes(); for (Class<?> clz : clzs) { String className = getName(clz); builder.append(className).append(PARAM_CLASS_SPLIT); } return builder.substring(0, builder.length() - 1); } /** * 获取方法的标示 : method_name + "(" + paramDesc + ")" * * @param method * @return */ public static String getMethodDesc(Method method) { String methodParamDesc = getMethodParamDesc(method); return getMethodDesc(method.getName(), methodParamDesc); } /** * 获取方法的标示 : method_name + "(" + paramDesc + ")" * * @param * @return */ public static String getMethodDesc(String methodName, String paramDesc) { if (paramDesc == null) { return methodName + "()"; } else { return methodName + "(" + paramDesc + ")"; } } public static Class<?>[] forNames(String classList) throws ClassNotFoundException { if (classList == null || "".equals(classList) || EMPTY_PARAM.equals(classList)) { return EMPTY_CLASS_ARRAY; } String[] classNames = classList.split(PARAM_CLASS_SPLIT); Class<?>[] classTypes = new Class<?>[classNames.length]; for (int i = 0; i < classNames.length; i++) { String className = classNames[i]; classTypes[i] = forName(className); } return classTypes; } public static Class<?> forName(String className) throws ClassNotFoundException { if (null == className || "".equals(className)) { return null; } Class<?> clz = name2ClassCache.get(className); if (clz != null) { return clz; } clz = forNameWithoutCache(className); // 应该没有内存消耗过多的可能,除非有些代码很恶心,创建特别多的类 name2ClassCache.putIfAbsent(className, clz); return clz; } private static Class<?> forNameWithoutCache(String className) throws ClassNotFoundException { if (!className.endsWith("[]")) { // not array Class<?> clz = getPrimitiveClass(className); clz = (clz != null) ? clz : Class.forName(className, true, Thread.currentThread().getContextClassLoader()); return clz; } int dimensionSiz = 0; while (className.endsWith("[]")) { dimensionSiz++; className = className.substring(0, className.length() - 2); } int[] dimensions = new int[dimensionSiz]; Class<?> clz = getPrimitiveClass(className); if (clz == null) { clz = Class.forName(className, true, Thread.currentThread().getContextClassLoader()); } return Array.newInstance(clz, dimensions).getClass(); } /** * 需要支持一维数组、二维数组等 * * @param * @return */ public static String getName(Class<?> clz) { if (clz == null) { return null; } String className = class2NameCache.get(clz); if (className != null) { return className; } className = getNameWithoutCache(clz); // 与name2ClassCache同样道理,如果没有恶心的代码,这块内存大小应该可控 class2NameCache.putIfAbsent(clz, className); return className; } private static String getNameWithoutCache(Class<?> clz) { if (!clz.isArray()) { return clz.getName(); } StringBuilder sb = new StringBuilder(); while (clz.isArray()) { sb.append("[]"); clz = clz.getComponentType(); } return clz.getName() + sb.toString(); } public static Class<?> getPrimitiveClass(String name) { // check if is primitive class if (name.length() <= PRIMITIVE_CLASS_NAME_MAX_LENGTH) { int index = Arrays.binarySearch(PRIMITIVE_NAMES, name); if (index >= 0) { return PRIMITIVE_CLASSES[index]; } } return null; } /** * 获取clz public method * * <pre> * 1)不包含构造函数 * 2)不包含Object.class * 3)包含该clz的父类的所有public方法 * </pre> * * @param clz * @return */ public static List<Method> getPublicMethod(Class<?> clz) { Method[] methods = clz.getMethods(); List<Method> ret = new ArrayList<Method>(); for (Method method : methods) { boolean isPublic = Modifier.isPublic(method.getModifiers()); boolean isNotObjectClass = method.getDeclaringClass() != Object.class; if (isPublic && isNotObjectClass) { ret.add(method); } } return ret; } public static Object getEmptyObject(Class<?> returnType) { return getEmptyObject(returnType, new HashMap<Class<?>, Object>(), 0); } private static Object getEmptyObject(Class<?> returnType, Map<Class<?>, Object> emptyInstances, int level) { if (level > 2) return null; if (returnType == null) { return null; } else if (returnType == boolean.class || returnType == Boolean.class) { return false; } else if (returnType == char.class || returnType == Character.class) { return '\0'; } else if (returnType == byte.class || returnType == Byte.class) { return (byte) 0; } else if (returnType == short.class || returnType == Short.class) { return (short) 0; } else if (returnType == int.class || returnType == Integer.class) { return 0; } else if (returnType == long.class || returnType == Long.class) { return 0L; } else if (returnType == float.class || returnType == Float.class) { return 0F; } else if (returnType == double.class || returnType == Double.class) { return 0D; } else if (returnType.isArray()) { return Array.newInstance(returnType.getComponentType(), 0); } else if (returnType.isAssignableFrom(ArrayList.class)) { return new ArrayList<Object>(0); } else if (returnType.isAssignableFrom(HashSet.class)) { return new HashSet<Object>(0); } else if (returnType.isAssignableFrom(HashMap.class)) { return new HashMap<Object, Object>(0); } else if (String.class.equals(returnType)) { return ""; } else if (!returnType.isInterface()) { try { Object value = emptyInstances.get(returnType); if (value == null) { value = returnType.newInstance(); emptyInstances.put(returnType, value); } Class<?> cls = value.getClass(); while (cls != null && cls != Object.class) { Field[] fields = cls.getDeclaredFields(); for (Field field : fields) { Object property = getEmptyObject(field.getType(), emptyInstances, level + 1); if (property != null) { try { if (!field.isAccessible()) { field.setAccessible(true); } field.set(value, property); } catch (Throwable e) {} } } cls = cls.getSuperclass(); } return value; } catch (Throwable e) { return null; } } else { return null; } } }