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

com.alibaba.dubbo.common.utils.ReflectUtils Maven / Gradle / Ivy

/*
 * 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.alibaba.dubbo.common.utils;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Date;
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;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtMethod;
import javassist.NotFoundException;

/**
 * ReflectUtils
 * 
 * @author qian.lei
 */
public final class ReflectUtils {
    
	/**
	 * void(V).
	 */
	public static final char JVM_VOID = 'V';

	/**
	 * boolean(Z).
	 */
	public static final char JVM_BOOLEAN = 'Z';

	/**
	 * byte(B).
	 */
	public static final char JVM_BYTE = 'B';

	/**
	 * char(C).
	 */
	public static final char JVM_CHAR = 'C';

	/**
	 * double(D).
	 */
	public static final char JVM_DOUBLE = 'D';

	/**
	 * float(F).
	 */
	public static final char JVM_FLOAT = 'F';

	/**
	 * int(I).
	 */
	public static final char JVM_INT = 'I';

	/**
	 * long(J).
	 */
	public static final char JVM_LONG = 'J';

	/**
	 * short(S).
	 */
	public static final char JVM_SHORT = 'S';

	public static final Class[] EMPTY_CLASS_ARRAY = new Class[0];

	public static final String JAVA_IDENT_REGEX = "(?:[_$a-zA-Z][_$a-zA-Z0-9]*)";

	public static final String JAVA_NAME_REGEX = "(?:" + JAVA_IDENT_REGEX + "(?:\\." + JAVA_IDENT_REGEX + ")*)";

	public static final String CLASS_DESC = "(?:L" + JAVA_IDENT_REGEX   + "(?:\\/" + JAVA_IDENT_REGEX + ")*;)";

	public static final String ARRAY_DESC  = "(?:\\[+(?:(?:[VZBCDFIJS])|" + CLASS_DESC + "))";

	public static final String DESC_REGEX = "(?:(?:[VZBCDFIJS])|" + CLASS_DESC + "|" + ARRAY_DESC + ")";

	public static final Pattern DESC_PATTERN = Pattern.compile(DESC_REGEX);

	public static final String METHOD_DESC_REGEX = "(?:("+JAVA_IDENT_REGEX+")?\\(("+DESC_REGEX+"*)\\)("+DESC_REGEX+")?)";

	public static final Pattern METHOD_DESC_PATTERN = Pattern.compile(METHOD_DESC_REGEX);

	public static final Pattern GETTER_METHOD_DESC_PATTERN = Pattern.compile("get([A-Z][_a-zA-Z0-9]*)\\(\\)(" + DESC_REGEX + ")");

	public static final Pattern SETTER_METHOD_DESC_PATTERN = Pattern.compile("set([A-Z][_a-zA-Z0-9]*)\\((" + DESC_REGEX + ")\\)V");

	public static final Pattern IS_HAS_CAN_METHOD_DESC_PATTERN = Pattern.compile("(?:is|has|can)([A-Z][_a-zA-Z0-9]*)\\(\\)Z");
	
	private static final ConcurrentMap>  DESC_CLASS_CACHE = new ConcurrentHashMap>();
    
	private static final ConcurrentMap>  NAME_CLASS_CACHE = new ConcurrentHashMap>();
	    
	private static final ConcurrentMap  Signature_METHODS_CACHE = new ConcurrentHashMap();
	
	public static boolean isPrimitives(Class cls) {
        if (cls.isArray()) {
            return isPrimitive(cls.getComponentType());
        }
        return isPrimitive(cls);
    }
    
	public static boolean isPrimitive(Class cls) {
        return cls.isPrimitive() || cls == String.class || cls == Boolean.class || cls == Character.class 
                || Number.class.isAssignableFrom(cls) || Date.class.isAssignableFrom(cls);
    }
	
	public static Class getBoxedClass(Class c) {
	    if( c == int.class )
            c = Integer.class;
        else if( c == boolean.class )
            c = Boolean.class;
        else  if( c == long.class )
            c = Long.class;
        else if( c == float.class )
            c = Float.class;
        else if( c == double.class )
            c = Double.class;
        else if( c == char.class )
            c = Character.class;
        else if( c == byte.class )
            c = Byte.class;
        else if( c == short.class )
            c = Short.class;
	    return c;
	}
	
	/**
	 * is compatible.
	 * 
	 * @param c class.
	 * @param o instance.
	 * @return compatible or not.
	 */
	public static boolean isCompatible(Class c, Object o)
	{
		boolean pt = c.isPrimitive();
		if( o == null )
			return !pt;

		if( pt )
		{
			if( c == int.class )
				c = Integer.class;
			else if( c == boolean.class )
				c = Boolean.class;
			else  if( c == long.class )
				c = Long.class;
			else if( c == float.class )
				c = Float.class;
			else if( c == double.class )
				c = Double.class;
			else if( c == char.class )
				c = Character.class;
			else if( c == byte.class )
				c = Byte.class;
			else if( c == short.class )
				c = Short.class;
		}
		if( c == o.getClass() )
			return true;
		return c.isInstance(o);
	}

	/**
	 * is compatible.
	 * 
	 * @param cs class array.
	 * @param os object array.
	 * @return compatible or not.
	 */
	public static boolean isCompatible(Class[] cs, Object[] os)
	{
		int len = cs.length;
		if( len != os.length ) return false;
		if( len == 0 ) return true;
		for(int i=0;i cls) {
	    if (cls == null)
	        return null;
	    ProtectionDomain domain = cls.getProtectionDomain();
	    if (domain == null)
	        return null;
	    CodeSource source = domain.getCodeSource();
	    if (source == null)
	        return null;
	    URL location = source.getLocation();
	    if (location == null)
            return null;
	    return location.getFile();
	}

	/**
	 * get name.
	 * java.lang.Object[][].class => "java.lang.Object[][]"
	 * 
	 * @param c class.
	 * @return name.
	 */
	public static String getName(Class c)
	{
		if( c.isArray() )
		{
			StringBuilder sb = new StringBuilder();
			do
			{
				sb.append("[]");
				c = c.getComponentType();
			}
			while( c.isArray() );

			return c.getName() + sb.toString();
		}
		return c.getName();
	}
	
    
    public static Class getGenericClass(Class cls) {
        return getGenericClass(cls, 0);
    }

    public static Class getGenericClass(Class cls, int i) {
        try {
            ParameterizedType parameterizedType = ((ParameterizedType) cls.getGenericInterfaces()[0]);
            Object genericClass = parameterizedType.getActualTypeArguments()[i];
            if (genericClass instanceof ParameterizedType) { // 处理多级泛型
                return (Class) ((ParameterizedType) genericClass).getRawType();
            } else if (genericClass instanceof GenericArrayType) { // 处理数组泛型
                return (Class) ((GenericArrayType) genericClass).getGenericComponentType();
            } else {
                return (Class) genericClass;
            }
        } catch (Throwable e) {
            throw new IllegalArgumentException(cls.getName()
                    + " generic type undefined!", e);
        }
    }


	/**
	 * get method name.
	 * "void do(int)", "void do()", "int do(java.lang.String,boolean)"
	 * 
	 * @param m method.
	 * @return name.
	 */
	public static String getName(final Method m)
	{
		StringBuilder ret = new StringBuilder();
		ret.append(getName(m.getReturnType())).append(' ');
		ret.append(m.getName()).append('(');
		Class[] parameterTypes = m.getParameterTypes();
		for(int i=0;i 0 )
				ret.append(',');
			ret.append(getName(parameterTypes[i]));
		}
		ret.append(')');
		return ret.toString();
	}
	
	public static String getSignature(String methodName, Class[] parameterTypes) {
		StringBuilder sb = new StringBuilder(methodName);
		sb.append("(");
		if (parameterTypes != null && parameterTypes.length > 0) {
			boolean first = true;
			for (Class type : parameterTypes) {
				if (first) {
					first = false;
				} else {
					sb.append(",");
				}
				sb.append(type.getName());
			}
		}
		sb.append(")");
		return sb.toString();
	}

	/**
	 * get constructor name.
	 * "()", "(java.lang.String,int)"
	 * 
	 * @param c constructor.
	 * @return name.
	 */
	public static String getName(final Constructor c)
	{
		StringBuilder ret = new StringBuilder("(");
		Class[] parameterTypes = c.getParameterTypes();
		for(int i=0;i 0 )
				ret.append(',');
			ret.append(getName(parameterTypes[i]));
		}
		ret.append(')');
		return ret.toString();
	}

	/**
	 * get class desc.
	 * boolean[].class => "[Z"
	 * Object.class => "Ljava/lang/Object;"
	 * 
	 * @param c class.
	 * @return desc.
	 * @throws NotFoundException 
	 */
	public static String getDesc(Class c)
	{
		StringBuilder ret = new StringBuilder();

		while( c.isArray() )
		{
			ret.append('[');
			c = c.getComponentType();
		}

		if( c.isPrimitive() )
		{
			String t = c.getName();
			if( "void".equals(t) ) ret.append(JVM_VOID);
			else if( "boolean".equals(t) ) ret.append(JVM_BOOLEAN);
			else if( "byte".equals(t) ) ret.append(JVM_BYTE);
			else if( "char".equals(t) ) ret.append(JVM_CHAR);
			else if( "double".equals(t) ) ret.append(JVM_DOUBLE);
			else if( "float".equals(t) ) ret.append(JVM_FLOAT);
			else if( "int".equals(t) ) ret.append(JVM_INT);
			else if( "long".equals(t) ) ret.append(JVM_LONG);
			else if( "short".equals(t) ) ret.append(JVM_SHORT);
		}
		else
		{
			ret.append('L');
			ret.append(c.getName().replace('.', '/'));
			ret.append(';');
		}
		return ret.toString();
	}

	/**
	 * get class array desc.
	 * [int.class, boolean[].class, Object.class] => "I[ZLjava/lang/Object;"
	 * 
	 * @param cs class array.
	 * @return desc.
	 * @throws NotFoundException 
	 */
	public static String getDesc(final Class[] cs)
	{
		if( cs.length == 0 )
			return "";

		StringBuilder sb = new StringBuilder(64);
		for( Class c : cs )
			sb.append(getDesc(c));
		return sb.toString();
	}

	/**
	 * get method desc.
	 * int do(int arg1) => "do(I)I"
	 * void do(String arg1,boolean arg2) => "do(Ljava/lang/String;Z)V"
	 * 
	 * @param m method.
	 * @return desc.
	 */
	public static String getDesc(final Method m)
	{
		StringBuilder ret = new StringBuilder(m.getName()).append('(');
		Class[] parameterTypes = m.getParameterTypes();
		for(int i=0;i c)
	{
		StringBuilder ret = new StringBuilder("(");
		Class[] parameterTypes = c.getParameterTypes();
		for(int i=0;i[] parameterTypes = m.getParameterTypes();
		for(int i=0;i "Ljava/lang/Object;"
	 * boolean[].class => "[Z"
	 * 
	 * @param c class.
	 * @return desc.
	 * @throws NotFoundException 
	 */
	public static String getDesc(final CtClass c) throws NotFoundException
	{
		StringBuilder ret = new StringBuilder();
		if( c.isArray() )
		{
			ret.append('[');
			ret.append(getDesc(c.getComponentType()));
		}
		else if( c.isPrimitive() )
		{
			String t = c.getName();
			if( "void".equals(t) ) ret.append(JVM_VOID);
			else if( "boolean".equals(t) ) ret.append(JVM_BOOLEAN);
			else if( "byte".equals(t) ) ret.append(JVM_BYTE);
			else if( "char".equals(t) ) ret.append(JVM_CHAR);
			else if( "double".equals(t) ) ret.append(JVM_DOUBLE);
			else if( "float".equals(t) ) ret.append(JVM_FLOAT);
			else if( "int".equals(t) ) ret.append(JVM_INT);
			else if( "long".equals(t) ) ret.append(JVM_LONG);
			else if( "short".equals(t) ) ret.append(JVM_SHORT);
		}
		else
		{
			ret.append('L');
			ret.append(c.getName().replace('.','/'));
			ret.append(';');
		}
		return ret.toString();
	}

	/**
	 * get method desc.
	 * "do(I)I", "do()V", "do(Ljava/lang/String;Z)V"
	 * 
	 * @param m method.
	 * @return desc.
	 */
	public static String getDesc(final CtMethod m) throws NotFoundException
	{
		StringBuilder ret = new StringBuilder(m.getName()).append('(');
		CtClass[] parameterTypes = m.getParameterTypes();
		for(int i=0;i "[[Ljava/util/Map;"
	 * 
	 * @param name name.
	 * @return desc.
	 */
	public static String name2desc(String name)
	{
		StringBuilder sb = new StringBuilder();
		int c = 0,index = name.indexOf('[');
		if( index > 0 )
		{
			c = ( name.length() - index ) / 2;
			name = name.substring(0,index);
		}
		while( c-- > 0 ) sb.append("[");
		if( "void".equals(name) ) sb.append(JVM_VOID);
		else if( "boolean".equals(name) ) sb.append(JVM_BOOLEAN);
		else if( "byte".equals(name) ) sb.append(JVM_BYTE);
		else if( "char".equals(name) ) sb.append(JVM_CHAR);
		else if( "double".equals(name) ) sb.append(JVM_DOUBLE);
		else if( "float".equals(name) ) sb.append(JVM_FLOAT);
		else if( "int".equals(name) ) sb.append(JVM_INT);
		else if( "long".equals(name) ) sb.append(JVM_LONG);
		else if( "short".equals(name) ) sb.append(JVM_SHORT);
		else sb.append('L').append(name.replace('.', '/')).append(';');
		return sb.toString();
	}

	/**
	 * desc to name.
	 * "[[I" => "int[][]"
	 * 
	 * @param desc desc.
	 * @return name.
	 */
	public static String desc2name(String desc)
	{
		StringBuilder sb = new StringBuilder();
		int c = desc.lastIndexOf('[') + 1;
		if( desc.length() == c+1 )
		{
			switch( desc.charAt(c) )
			{
				case JVM_VOID: { sb.append("void"); break; }
				case JVM_BOOLEAN: { sb.append("boolean"); break; }
				case JVM_BYTE: { sb.append("byte"); break; }
				case JVM_CHAR: { sb.append("char"); break; }
				case JVM_DOUBLE: { sb.append("double"); break; }
				case JVM_FLOAT: { sb.append("float"); break; }
				case JVM_INT: { sb.append("int"); break; }
				case JVM_LONG: { sb.append("long"); break; }
				case JVM_SHORT: { sb.append("short"); break; }
				default:
					throw new RuntimeException();
			}
		}
		else
		{
			sb.append(desc.substring(c+1, desc.length()-1).replace('/','.'));
		}
		while( c-- > 0 ) sb.append("[]");
		return sb.toString();
	}
	
	public static Class forName(String name) {
		try {
			return name2class(name);
		} catch (ClassNotFoundException e) {
			throw new IllegalStateException("Not found class " + name + ", cause: " + e.getMessage(), e);
		}
	}

	/**
	 * name to class.
	 * "boolean" => boolean.class
	 * "java.util.Map[][]" => java.util.Map[][].class
	 * 
	 * @param name name.
	 * @return Class instance.
	 */
	public static Class name2class(String name) throws ClassNotFoundException
	{
		return name2class(ClassHelper.getClassLoader(), name);
	}

	/**
	 * name to class.
	 * "boolean" => boolean.class
	 * "java.util.Map[][]" => java.util.Map[][].class
	 * 
	 * @param cl ClassLoader instance.
	 * @param name name.
	 * @return Class instance.
	 */
	private static Class name2class(ClassLoader cl, String name) throws ClassNotFoundException
	{
		int c = 0, index = name.indexOf('[');
		if( index > 0 )
		{
			c = ( name.length() - index ) / 2;
			name = name.substring(0, index);
		}
		if( c > 0 )
		{
			StringBuilder sb = new StringBuilder();
			while( c-- > 0 )
				sb.append("[");

			if( "void".equals(name) ) sb.append(JVM_VOID);
			else if( "boolean".equals(name) ) sb.append(JVM_BOOLEAN);
			else if( "byte".equals(name) ) sb.append(JVM_BYTE);
			else if( "char".equals(name) ) sb.append(JVM_CHAR);
			else if( "double".equals(name) ) sb.append(JVM_DOUBLE);
			else if( "float".equals(name) ) sb.append(JVM_FLOAT);
			else if( "int".equals(name) ) sb.append(JVM_INT);
			else if( "long".equals(name) ) sb.append(JVM_LONG);
			else if( "short".equals(name) ) sb.append(JVM_SHORT);
			else sb.append('L').append(name).append(';'); // "java.lang.Object" ==> "Ljava.lang.Object;"
			name = sb.toString();
		}
		else
		{
			if( "void".equals(name) ) return void.class;
			else if( "boolean".equals(name) ) return boolean.class;
			else if( "byte".equals(name) ) return byte.class;
			else if( "char".equals(name) ) return char.class;
			else if( "double".equals(name) ) return double.class;
			else if( "float".equals(name) ) return float.class;
			else if( "int".equals(name) ) return int.class;
			else if( "long".equals(name) ) return long.class;
			else if( "short".equals(name) ) return short.class;
		}

		if( cl == null )
			cl = ClassHelper.getClassLoader();
		Class clazz = NAME_CLASS_CACHE.get(name);
        if(clazz == null){
            clazz = Class.forName(name, true, cl);
            NAME_CLASS_CACHE.put(name, clazz);
        }
        return clazz;
	}

	/**
	 * desc to class.
	 * "[Z" => boolean[].class
	 * "[[Ljava/util/Map;" => java.util.Map[][].class
	 * 
	 * @param desc desc.
	 * @return Class instance.
	 * @throws ClassNotFoundException 
	 */
	public static Class desc2class(String desc) throws ClassNotFoundException
	{
		return desc2class(ClassHelper.getClassLoader(), desc);
	}

	/**
	 * desc to class.
	 * "[Z" => boolean[].class
	 * "[[Ljava/util/Map;" => java.util.Map[][].class
	 * 
	 * @param cl ClassLoader instance.
	 * @param desc desc.
	 * @return Class instance.
	 * @throws ClassNotFoundException 
	 */
	private static Class desc2class(ClassLoader cl, String desc) throws ClassNotFoundException
	{
		switch( desc.charAt(0) )
		{
			case JVM_VOID: return void.class;
			case JVM_BOOLEAN: return boolean.class;
			case JVM_BYTE: return byte.class;
			case JVM_CHAR: return char.class;
			case JVM_DOUBLE: return double.class;
			case JVM_FLOAT: return float.class;
			case JVM_INT: return int.class;
			case JVM_LONG: return long.class;
			case JVM_SHORT: return short.class;
			case 'L':
				desc = desc.substring(1, desc.length()-1).replace('/', '.'); // "Ljava/lang/Object;" ==> "java.lang.Object"
				break;
			case '[':
				desc = desc.replace('/', '.');  // "[[Ljava/lang/Object;" ==> "[[Ljava.lang.Object;"
				break;
			default:
				throw new ClassNotFoundException("Class not found: " + desc);
		}

		if( cl == null )
			cl = ClassHelper.getClassLoader();
		Class clazz = DESC_CLASS_CACHE.get(desc);
		if(clazz==null){
		    clazz = Class.forName(desc, true, cl);
		    DESC_CLASS_CACHE.put(desc, clazz);
		}
		return clazz;
	}

	/**
	 * get class array instance.
	 * 
	 * @param desc desc.
	 * @return Class class array.
	 * @throws ClassNotFoundException 
	 */
	public static Class[] desc2classArray(String desc) throws ClassNotFoundException
	{
	    Class[] ret = desc2classArray(ClassHelper.getClassLoader(), desc);
		return ret;
	}

	/**
	 * get class array instance.
	 * 
	 * @param cl ClassLoader instance.
	 * @param desc desc.
	 * @return Class[] class array.
	 * @throws ClassNotFoundException 
	 */
	private static Class[] desc2classArray(ClassLoader cl, String desc) throws ClassNotFoundException
	{
		if( desc.length() == 0 )
			return EMPTY_CLASS_ARRAY;

		List> cs = new ArrayList>();
		Matcher m = DESC_PATTERN.matcher(desc);
		while(m.find())
			cs.add(desc2class(cl, m.group()));
		return cs.toArray(EMPTY_CLASS_ARRAY);
	}

	/**
	 * 根据方法签名从类中找出方法。
	 * 
	 * @param clazz 查找的类。
	 * @param methodName 方法签名,形如method1(int, String)。也允许只给方法名不参数只有方法名,形如method2。
	 * @return 返回查找到的方法。
	 * @throws NoSuchMethodException
	 * @throws ClassNotFoundException  
	 * @throws IllegalStateException 给定的方法签名找到多个方法(方法签名中没有指定参数,又有有重载的方法的情况)
	 */
	public static Method findMethodByMethodSignature(Class clazz, String methodName, String[] parameterTypes)
	        throws NoSuchMethodException, ClassNotFoundException {
	    String signature = methodName;
        if(parameterTypes != null && parameterTypes.length > 0){
            signature = methodName + StringUtils.join(parameterTypes);
        }
        Method method = Signature_METHODS_CACHE.get(signature);
        if(method != null){
            return method;
        }
	    if (parameterTypes == null) {
            List finded = new ArrayList();
            for (Method m : clazz.getMethods()) {
                if (m.getName().equals(methodName)) {
                    finded.add(m);
                }
            }
            if (finded.isEmpty()) {
                throw new NoSuchMethodException("No such method " + methodName + " in class " + clazz);
            }
            if(finded.size() > 1) {
                String msg = String.format("Not unique method for method name(%s) in class(%s), find %d methods.",
                        methodName, clazz.getName(), finded.size());
                throw new IllegalStateException(msg);
            }
            method = finded.get(0);
        } else {
            Class[] types = new Class[parameterTypes.length];
            for (int i = 0; i < parameterTypes.length; i ++) {
                types[i] = ReflectUtils.name2class(parameterTypes[i]);
            }
            method = clazz.getMethod(methodName, types);
            
        }
	    Signature_METHODS_CACHE.put(signature, method);
        return method;
	}

    public static Method findMethodByMethodName(Class clazz, String methodName)
    		throws NoSuchMethodException, ClassNotFoundException {
    	return findMethodByMethodSignature(clazz, methodName, null);
    }
    
    public static Constructor findConstructor(Class clazz, Class paramType) throws NoSuchMethodException {
    	Constructor targetConstructor;
		try {
			targetConstructor = clazz.getConstructor(new Class[] {paramType});
		} catch (NoSuchMethodException e) {
			targetConstructor = null;
			Constructor[] constructors = clazz.getConstructors();
			for (Constructor constructor : constructors) {
				if (Modifier.isPublic(constructor.getModifiers()) 
						&& constructor.getParameterTypes().length == 1
						&& constructor.getParameterTypes()[0].isAssignableFrom(paramType)) {
					targetConstructor = constructor;
					break;
				}
			}
			if (targetConstructor == null) {
				throw e;
			}
		}
		return targetConstructor;
    }

    /**
     * 检查对象是否是指定接口的实现。
     * 

* 不会触发到指定接口的{@link Class},所以如果ClassLoader中没有指定接口类时,也不会出错。 * * @param obj 要检查的对象 * @param interfaceClazzName 指定的接口名 * @return 返回{@code true},如果对象实现了指定接口;否则返回{@code false}。 */ public static boolean isInstance(Object obj, String interfaceClazzName) { for (Class clazz = obj.getClass(); clazz != null && !clazz.equals(Object.class); clazz = clazz.getSuperclass()) { Class[] interfaces = clazz.getInterfaces(); for (Class itf : interfaces) { if (itf.getName().equals(interfaceClazzName)) { return true; } } } return false; } public static Object getEmptyObject(Class returnType) { return getEmptyObject(returnType, new HashMap, Object>(), 0); } private static Object getEmptyObject(Class returnType, Map, 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(0); } else if (returnType.isAssignableFrom(HashSet.class)) { return new HashSet(0); } else if (returnType.isAssignableFrom(HashMap.class)) { return new HashMap(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; } } public static boolean isBeanPropertyReadMethod(Method method) { return method != null && Modifier.isPublic(method.getModifiers()) && ! Modifier.isStatic(method.getModifiers()) && method.getReturnType() != void.class && method.getDeclaringClass() != Object.class && method.getParameterTypes().length == 0 && ((method.getName().startsWith("get") && method.getName().length() > 3) || (method.getName().startsWith("is") && method.getName().length() > 2)); } public static String getPropertyNameFromBeanReadMethod(Method method) { if (isBeanPropertyReadMethod(method)) { if (method.getName().startsWith("get")) { return method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4); } if (method.getName().startsWith("is")) { return method.getName().substring(2, 3).toLowerCase() + method.getName().substring(3); } } return null; } public static boolean isBeanPropertyWriteMethod(Method method) { return method != null && Modifier.isPublic(method.getModifiers()) && ! Modifier.isStatic(method.getModifiers()) && method.getDeclaringClass() != Object.class && method.getParameterTypes().length == 1 && method.getName().startsWith("set") && method.getName().length() > 3; } public static String getPropertyNameFromBeanWriteMethod(Method method) { if (isBeanPropertyWriteMethod(method)) { return method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4); } return null; } public static boolean isPublicInstanceField(Field field) { return Modifier.isPublic(field.getModifiers()) && !Modifier.isStatic(field.getModifiers()) && !Modifier.isFinal(field.getModifiers()) && !field.isSynthetic(); } public static Map getBeanPropertyFields(Class cl) { Map properties = new HashMap(); for(; cl != null; cl = cl.getSuperclass()) { Field[] fields = cl.getDeclaredFields(); for(Field field : fields) { if (Modifier.isTransient(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) { continue; } field.setAccessible(true); properties.put(field.getName(), field); } } return properties; } public static Map getBeanPropertyReadMethods(Class cl) { Map properties = new HashMap(); for(; cl != null; cl = cl.getSuperclass()) { Method[] methods = cl.getDeclaredMethods(); for(Method method : methods) { if (isBeanPropertyReadMethod(method)) { method.setAccessible(true); String property = getPropertyNameFromBeanReadMethod(method); properties.put(property, method); } } } return properties; } private ReflectUtils(){} }