001package net.gdface.utils;
002
003import static com.google.common.base.Preconditions.*;
004import java.lang.reflect.Constructor;
005import java.lang.reflect.Field;
006import java.lang.reflect.Method;
007import java.lang.reflect.Modifier;
008import java.util.Collections;
009import java.util.LinkedHashMap;
010import java.util.Map;
011
012import com.google.common.base.MoreObjects;
013import com.google.common.base.Strings;
014import com.google.common.base.Throwables;
015import com.google.common.collect.ForwardingMap;
016
017/**
018 * @author guyadong
019 *
020 */
021public class ReflectionUtils {
022        public static final String PROP_CLASSNAME = "className";
023        public static final String PROP_STATICMETHODNAME = "staticMethodName";
024        public static final String PROP_PARAMETERTYPES = "parameterTypes";
025        public static final String PROP_CONSTRUCTORARGS = "constructorArgs";
026        public static final String PROP_CONSTRUCTORPARAMS = "constructorParams";
027        private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
028        private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
029        public ReflectionUtils() {
030        }
031        private static class ParameterMap extends ForwardingMap<String,Object>{
032                private final Map<String, Object> delegate;
033                public ParameterMap(Map<String, Object> delegate) {
034                        super();
035                        if(null == delegate){
036                                this.delegate = Collections.emptyMap();
037                        }else{
038                                this.delegate = delegate;
039                        }
040                }
041                @Override
042                protected Map<String, Object> delegate() {
043                        return delegate;
044                }
045                @SuppressWarnings("unchecked")
046                public final <T> T of(String key,T defaultValue){
047                        checkArgument(null != key);
048                        Object value = delegate.get(key);
049                        try{
050                                return null == value ? defaultValue: (T) value;
051                        }catch(ClassCastException e){
052                                throw new IllegalArgumentException("invalid parameter: " + key + ",caused by " + e.getMessage());
053                        }
054                }
055                public final <T> T of(String key){
056                        return of(key,null);
057                }
058        }
059        @SuppressWarnings("unchecked")
060        public static <T> Class<? extends T> getInstanceClass(Class<T> superClass,String instanceClassName) 
061                        throws ClassNotFoundException{
062                checkArgument(null != superClass && !Strings.isNullOrEmpty(instanceClassName));
063                Class<?> instanceClass = (Class<?>) Class.forName(instanceClassName);
064                checkInstanceClass(superClass,instanceClass);
065                return  (Class<? extends T>)instanceClass;
066        }
067        public static <T> T getInstance(Class<T> superClass,Map<String,Object> params) 
068                        throws NoSuchMethodException, ClassNotFoundException{
069                ParameterMap paramMap = new ParameterMap(params);
070                String clazzName = paramMap.of(PROP_CLASSNAME);
071                Class<? extends T> instanceClass = getInstanceClass(superClass,clazzName);
072                String staticMethodName =paramMap.of(PROP_STATICMETHODNAME);
073                if(null != staticMethodName){
074                        try{
075                                return getInstanceByStaticMethod(superClass,instanceClass,staticMethodName);
076                        }catch(NoSuchMethodException e){
077                                // 找不到静态方法则尝试用构造方法创建实例
078                        }
079                }
080                if(paramMap.containsKey(PROP_CONSTRUCTORPARAMS)){
081                        LinkedHashMap<Class<?>,Object> constructorParams = paramMap.of(PROP_CONSTRUCTORPARAMS);
082                        return getInstanceByConstructor(superClass,instanceClass,constructorParams);
083                }else{
084                        Class<?>[] parameterTypes = paramMap.of(PROP_PARAMETERTYPES);
085                        Object[] ctorArgs = paramMap.of(PROP_CONSTRUCTORARGS);
086                        return getInstanceByConstructor(superClass,instanceClass,parameterTypes,ctorArgs);
087                }
088        }
089        private static void checkInstanceClass(Class<?> superClass,Class<?> instanceClass){
090                checkArgument(null != superClass && null != instanceClass);
091                checkArgument(!instanceClass.isInterface() && superClass.isAssignableFrom(instanceClass),
092                                "%s not a implemenation of %s",instanceClass.getName(),superClass.getSimpleName());
093                checkArgument(!Modifier.isAbstract(instanceClass.getModifiers()),
094                                "%s is abstract class",instanceClass.getName());
095                checkArgument(Modifier.isStatic(instanceClass.getModifiers()) || null == instanceClass.getDeclaringClass(),
096                                "%s is not static class",instanceClass.getName());
097        }
098        public static <T> T getInstanceByConstructor(Class<T> superClass,Class<? extends T> instanceClass,Class<?>[] parameterTypes,Object[] constructorArgs) 
099                        throws NoSuchMethodException{
100                checkInstanceClass(superClass,instanceClass);
101                parameterTypes = MoreObjects.firstNonNull(parameterTypes, EMPTY_CLASS_ARRAY);
102                constructorArgs = MoreObjects.firstNonNull(constructorArgs, EMPTY_OBJECT_ARRAY);
103                checkArgument(parameterTypes.length == constructorArgs.length);
104                try{
105                        Constructor<? extends T> ctor = instanceClass.getConstructor(parameterTypes);
106                        try {
107                                return ctor.newInstance(constructorArgs);
108                        } catch (Exception e) {
109                                Throwables.throwIfUnchecked(e);
110                                throw new RuntimeException(e);
111                        }
112                } finally{}
113        }
114        public static <T> T getInstanceByConstructor(Class<T> superClass,Class<? extends T> instanceClass,LinkedHashMap<Class<?>,Object> constructorParams) 
115                        throws NoSuchMethodException{
116                checkInstanceClass(superClass,instanceClass);
117                constructorParams = MoreObjects.firstNonNull(constructorParams, new LinkedHashMap<Class<?>,Object>());
118                Class<?>[] parameterTypes = constructorParams.keySet().toArray(new Class<?>[constructorParams.size()]);
119                Object[] initargs = constructorParams.values().toArray(new Object[constructorParams.size()]);
120                Constructor<? extends T> ctor = instanceClass.getConstructor(parameterTypes);
121                try {
122                        return ctor.newInstance(initargs);
123                } catch (Exception e) {
124                        Throwables.throwIfUnchecked(e);
125                        throw new RuntimeException(e);
126                }
127        }
128        @SuppressWarnings("unchecked")
129        public static <T> T getInstanceByStaticMethod(Class<T> superClass,Class<? extends T> instanceClass,String staticMethodName) 
130                        throws NoSuchMethodException{
131                checkArgument(!Strings.isNullOrEmpty(staticMethodName));
132                checkInstanceClass(superClass,instanceClass);
133                try {
134                        Method method = instanceClass.getMethod(staticMethodName);
135                        checkArgument(Modifier.isStatic(method.getModifiers()),"%s is not a static method",method.toString());
136                        checkArgument(superClass.isAssignableFrom(method.getReturnType()),"unexpect return type %s",method.getReturnType().toString());
137                        try{
138                                return (T) method.invoke(null);
139                        }catch(ClassCastException e){
140                                throw new IllegalArgumentException(
141                                                String.format("invalid return type of static method %s caused by %s",method.toString(),e.getMessage()));
142                        }
143                } catch(NoSuchMethodException e){
144                        throw e;
145                }catch (Exception e) {
146                        Throwables.throwIfUnchecked(e);
147                        throw new RuntimeException(e);
148                }
149        }
150        /**
151         * 反射获取{@code object}的私有成员
152         * @param object
153         * @param name
154         * @return 成员对象
155         */
156        @SuppressWarnings("unchecked")
157        public static <T> T valueOfField(Object object,String name){
158                try {
159                        Field field = checkNotNull(object,"object is null").getClass().getDeclaredField(checkNotNull(name,"name is null"));
160                        field.setAccessible(true);
161                        return (T) field.get(object);
162                } catch (Exception e) {
163                        Throwables.throwIfUnchecked(e);
164                        throw new RuntimeException(e);
165                }
166        }
167}