001/* Copyright (C) 2013 TU Dortmund
002 * This file is part of AutomataLib, http://www.automatalib.net/.
003 * 
004 * AutomataLib is free software; you can redistribute it and/or
005 * modify it under the terms of the GNU Lesser General Public
006 * License version 3.0 as published by the Free Software Foundation.
007 * 
008 * AutomataLib is distributed in the hope that it will be useful,
009 * but WITHOUT ANY WARRANTY; without even the implied warranty of
010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
011 * Lesser General Public License for more details.
012 * 
013 * You should have received a copy of the GNU Lesser General Public
014 * License along with AutomataLib; if not, see
015 * http://www.gnu.de/documents/lgpl.en.html.
016 */
017package net.automatalib.commons.util;
018
019import java.lang.reflect.Constructor;
020import java.lang.reflect.Method;
021import java.util.HashMap;
022import java.util.Map;
023
024public abstract class ReflectUtil {
025        
026        private static final Class<?>[][] W2P_MAPPING = {
027                { Void.class, void.class },
028                { Boolean.class, boolean.class },
029                { Byte.class, byte.class },
030                { Character.class, char.class },
031                { Short.class, short.class },
032                { Integer.class, int.class },
033                { Long.class, long.class },
034                { Float.class, float.class },
035                { Double.class, double.class }
036        };
037        
038        private static final Map<Class<?>,Class<?>> w2pMap;
039
040        
041        static {
042                w2pMap = new HashMap<Class<?>,Class<?>>();
043                
044                for(Class<?>[] w2p : W2P_MAPPING)
045                        w2pMap.put(w2p[0], w2p[1]);
046        }
047        
048        private ReflectUtil() {}
049        
050        
051        
052        public static Class<?> wrapperToPrimitive(Class<?> wrapperClazz) {
053                Class<?> prim = w2pMap.get(wrapperClazz);
054                if(prim == null)
055                        return wrapperClazz;
056                return prim;
057        }
058        
059        public static Class<?>[] wrapperToPrimitive(Class<?> ...clazzes) {
060                Class<?>[] result = clazzes;
061                for(int i = 0; i < result.length; i++) {
062                        Class<?> curr = result[i];
063                        Class<?> prim = wrapperToPrimitive(curr);
064                        if(prim != curr) {
065                                if(result == clazzes)
066                                        result = clazzes.clone();
067                                result[i] = prim;
068                        }
069                }
070                
071                return result;
072        }
073        
074        public static boolean w2pEquals(Class<?> a, Class<?> b) {
075                a = wrapperToPrimitive(a);
076                b = wrapperToPrimitive(b);
077                return a.equals(b);
078        }
079        
080        public static boolean w2pEquals(Class<?>[] a, Class<?> ...b) {
081                if(a.length != b.length)
082                        return false;
083                
084                for(int i = 0; i < a.length; i++) {
085                        if(!w2pEquals(a[i], b[i]))
086                                return false;
087                }
088                
089                return true;
090        }
091        
092        
093        @SuppressWarnings("unchecked")
094        public static <T> Constructor<T> findConstructor(Class<T> clazz, Class<?> ...params)
095                        throws SecurityException, NoSuchMethodException {
096                try {
097                        return clazz.getConstructor(params);
098                } catch (NoSuchMethodException e) {
099                        Class<?>[] primParams = wrapperToPrimitive(params);
100                        if(primParams != params) {
101                                try {
102                                        return clazz.getConstructor(primParams);
103                                }
104                                catch(NoSuchMethodException e2) {}
105                        }
106                        
107                        Constructor<T>[] ctors = (Constructor<T>[])clazz.getConstructors();
108                                        
109                        for(Constructor<T> candidate : ctors) {
110                                if(w2pEquals(candidate.getParameterTypes(), params))
111                                        return candidate;
112                        }
113                        
114                        throw e;
115                }
116        }
117        
118        public static Method findMethod(Class<?> clazz, String name, Class<?> ...params)
119                        throws SecurityException, NoSuchMethodException {
120                try {
121                        return clazz.getMethod(name, params);
122                } catch (NoSuchMethodException e) {
123                        Class<?>[] primParams = wrapperToPrimitive(params);
124                        if(primParams != params) {
125                                try {
126                                        return clazz.getMethod(name, primParams);
127                                }
128                                catch(NoSuchMethodException e2) {}
129                        }
130                        
131                        Method[] methods = clazz.getMethods();
132                        
133                        for(Method candidate : methods) {
134                                if(w2pEquals(candidate.getParameterTypes()))
135                                        return candidate;
136                        }
137                        
138                        throw e;
139                }
140        }
141        
142        public static Method findMethodRT(Class<?> clazz, String name, Class<?> returnType, Class<?> ...params)
143                        throws SecurityException, NoSuchMethodException {
144                Method m = findMethod(clazz, name, params);
145                
146                if(returnType == null)
147                        return m;
148                
149                Class<?> rt = m.getReturnType();
150                
151                if(w2pEquals(rt, returnType) || returnType.isAssignableFrom(rt))
152                        return m;
153                
154                throw new NoSuchMethodException("Method with matching parameters but incompatible return type " + rt.getName()
155                                + " (expected " + returnType.getName() + ") found");
156        }
157}