001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.util;
016    
017    import java.lang.annotation.Annotation;
018    import java.lang.reflect.Constructor;
019    import java.lang.reflect.Field;
020    import java.lang.reflect.Method;
021    import java.lang.reflect.Modifier;
022    
023    import java.util.Arrays;
024    import java.util.List;
025    
026    /**
027     * @author Brian Wing Shun Chan
028     * @author Miguel Pastor
029     * @author Shuyang Zhou
030     */
031    public class ReflectionUtil {
032    
033            public static Class<?> getAnnotationDeclaringClass(
034                    Class<? extends Annotation> annotationClass, Class<?> clazz) {
035    
036                    if ((clazz == null) || clazz.equals(Object.class)) {
037                            return null;
038                    }
039    
040                    if (isAnnotationDeclaredInClass(annotationClass, clazz)) {
041                            return clazz;
042                    }
043                    else {
044                            return getAnnotationDeclaringClass(
045                                    annotationClass, clazz.getSuperclass());
046                    }
047            }
048    
049            public static Method getBridgeMethod(
050                            Class<?> clazz, String name, Class<?> ... parameterTypes)
051                    throws Exception {
052    
053                    return getBridgeMethod(true, clazz, name, parameterTypes);
054            }
055    
056            public static Method getDeclaredBridgeMethod(
057                            Class<?> clazz, String name, Class<?> ... parameterTypes)
058                    throws Exception {
059    
060                    return getBridgeMethod(false, clazz, name, parameterTypes);
061            }
062    
063            public static Field getDeclaredField(Class<?> clazz, String name)
064                    throws Exception {
065    
066                    Field field = clazz.getDeclaredField(name);
067    
068                    if (!field.isAccessible()) {
069                            field.setAccessible(true);
070                    }
071    
072                    int modifiers = field.getModifiers();
073    
074                    if ((modifiers & Modifier.FINAL) == Modifier.FINAL) {
075                            Field modifiersField = ReflectionUtil.getDeclaredField(
076                                    Field.class, "modifiers");
077    
078                            modifiersField.setInt(field, modifiers & ~Modifier.FINAL);
079                    }
080    
081                    return field;
082            }
083    
084            public static Method getDeclaredMethod(
085                            Class<?> clazz, String name, Class<?> ... parameterTypes)
086                    throws Exception {
087    
088                    Method method = clazz.getDeclaredMethod(name, parameterTypes);
089    
090                    if (!method.isAccessible()) {
091                            method.setAccessible(true);
092                    }
093    
094                    return method;
095            }
096    
097            public static Class<?>[] getInterfaces(Object object) {
098                    return getInterfaces(object, null);
099            }
100    
101            public static Class<?>[] getInterfaces(
102                    Object object, ClassLoader classLoader) {
103    
104                    List<Class<?>> interfaceClasses = new UniqueList<Class<?>>();
105    
106                    Class<?> clazz = object.getClass();
107    
108                    _getInterfaces(interfaceClasses, clazz, classLoader);
109    
110                    Class<?> superClass = clazz.getSuperclass();
111    
112                    while (superClass != null) {
113                            _getInterfaces(interfaceClasses, superClass, classLoader);
114    
115                            superClass = superClass.getSuperclass();
116                    }
117    
118                    return interfaceClasses.toArray(new Class<?>[interfaceClasses.size()]);
119            }
120    
121            public static Class<?>[] getParameterTypes(Object[] arguments) {
122                    if (arguments == null) {
123                            return null;
124                    }
125    
126                    Class<?>[] parameterTypes = new Class<?>[arguments.length];
127    
128                    for (int i = 0; i < arguments.length; i++) {
129                            if (arguments[i] == null) {
130                                    parameterTypes[i] = null;
131                            }
132                            else if (arguments[i] instanceof Boolean) {
133                                    parameterTypes[i] = Boolean.TYPE;
134                            }
135                            else if (arguments[i] instanceof Byte) {
136                                    parameterTypes[i] = Byte.TYPE;
137                            }
138                            else if (arguments[i] instanceof Character) {
139                                    parameterTypes[i] = Character.TYPE;
140                            }
141                            else if (arguments[i] instanceof Double) {
142                                    parameterTypes[i] = Double.TYPE;
143                            }
144                            else if (arguments[i] instanceof Float) {
145                                    parameterTypes[i] = Float.TYPE;
146                            }
147                            else if (arguments[i] instanceof Integer) {
148                                    parameterTypes[i] = Integer.TYPE;
149                            }
150                            else if (arguments[i] instanceof Long) {
151                                    parameterTypes[i] = Long.TYPE;
152                            }
153                            else if (arguments[i] instanceof Short) {
154                                    parameterTypes[i] = Short.TYPE;
155                            }
156                            else {
157                                    parameterTypes[i] = arguments[i].getClass();
158                            }
159                    }
160    
161                    return parameterTypes;
162            }
163    
164            public static boolean isAnnotationDeclaredInClass(
165                    Class<? extends Annotation> annotationClass, Class<?> clazz) {
166    
167                    if ((annotationClass == null) || (clazz == null)) {
168                            throw new IllegalArgumentException();
169                    }
170    
171                    Annotation[] annotations = clazz.getAnnotations();
172    
173                    for (Annotation annotation : annotations) {
174                            if (annotationClass.equals(annotation.annotationType())) {
175                                    return true;
176                            }
177                    }
178    
179                    return false;
180            }
181    
182            public static <T extends Enum<T>> T newEnumElement(
183                            Class<T> enumClass, Class<?>[] constructorParameterTypes,
184                            String name, int ordinal, Object... constructorParameters)
185                    throws Exception {
186    
187                    Class<?>[] parameterTypes = null;
188    
189                    if ((constructorParameterTypes != null) &&
190                            (constructorParameterTypes.length != 0)) {
191    
192                            parameterTypes = new Class<?>[constructorParameterTypes.length + 2];
193    
194                            parameterTypes[0] = String.class;
195                            parameterTypes[1] = int.class;
196    
197                            System.arraycopy(
198                                    constructorParameterTypes, 0, parameterTypes, 2,
199                                    constructorParameterTypes.length);
200                    }
201                    else {
202                            parameterTypes = new Class<?>[2];
203    
204                            parameterTypes[0] = String.class;
205                            parameterTypes[1] = int.class;
206                    }
207    
208                    Constructor<T> constructor = enumClass.getDeclaredConstructor(
209                            parameterTypes);
210    
211                    Method acquireConstructorAccessorMethod = getDeclaredMethod(
212                            Constructor.class, "acquireConstructorAccessor");
213    
214                    acquireConstructorAccessorMethod.invoke(constructor);
215    
216                    Field constructorAccessorField = getDeclaredField(
217                            Constructor.class, "constructorAccessor");
218    
219                    Object constructorAccessor = constructorAccessorField.get(constructor);
220    
221                    Method newInstanceMethod = getDeclaredMethod(
222                            constructorAccessor.getClass(), "newInstance", Object[].class);
223    
224                    Object[] parameters = null;
225    
226                    if ((constructorParameters != null) &&
227                            (constructorParameters.length != 0)) {
228    
229                            parameters = new Object[constructorParameters.length + 2];
230    
231                            parameters[0] = name;
232                            parameters[1] = ordinal;
233    
234                            System.arraycopy(
235                                    constructorParameters, 0, parameters, 2,
236                                    constructorParameters.length);
237                    }
238                    else {
239                            parameters = new Object[2];
240    
241                            parameters[0] = name;
242                            parameters[1] = ordinal;
243                    }
244    
245                    return (T)newInstanceMethod.invoke(
246                            constructorAccessor, new Object[] {parameters});
247            }
248    
249            public static <T extends Enum<T>> T newEnumElement(
250                            Class<T> enumClass, String name, int ordinal)
251                    throws Exception {
252    
253                    return newEnumElement(enumClass, null, name, ordinal, (Object[])null);
254            }
255    
256            protected static Method getBridgeMethod(
257                            boolean publicMethod, Class<?> clazz, String name,
258                            Class<?> ... parameterTypes)
259                    throws Exception {
260    
261                    Method method = null;
262    
263                    if (publicMethod) {
264                            method = clazz.getMethod(name, parameterTypes);
265                    }
266                    else {
267                            method = clazz.getDeclaredMethod(name, parameterTypes);
268                    }
269    
270                    if (method.isBridge()) {
271                            return method;
272                    }
273    
274                    Method[] methods = null;
275    
276                    if (publicMethod) {
277                            methods = clazz.getMethods();
278                    }
279                    else {
280                            methods = clazz.getDeclaredMethods();
281                    }
282    
283                    bridge:
284                    for (Method currentMethod : methods) {
285                            if (!currentMethod.isBridge() ||
286                                    !name.equals(currentMethod.getName())) {
287    
288                                    continue;
289                            }
290    
291                            Class<?>[] currentParameterTypes =
292                                    currentMethod.getParameterTypes();
293    
294                            if (currentParameterTypes.length != parameterTypes.length) {
295                                    continue;
296                            }
297    
298                            for (int i = 0; i < currentParameterTypes.length; i++) {
299                                    if (!currentParameterTypes[i].isAssignableFrom(
300                                                    parameterTypes[i])) {
301    
302                                            continue bridge;
303                                    }
304                            }
305    
306                            return currentMethod;
307                    }
308    
309                    throw new NoSuchMethodException(
310                            "No bridge method on " + clazz + " with name " + name +
311                                    " and parameter types " + Arrays.toString(parameterTypes));
312            }
313    
314            private static void _getInterfaces(
315                    List<Class<?>> interfaceClasses, Class<?> clazz,
316                    ClassLoader classLoader) {
317    
318                    for (Class<?> interfaceClass : clazz.getInterfaces()) {
319                            try {
320                                    if (classLoader != null) {
321                                            interfaceClasses.add(
322                                                    classLoader.loadClass(interfaceClass.getName()));
323                                    }
324                                    else {
325                                            interfaceClasses.add(interfaceClass);
326                                    }
327                            }
328                            catch (ClassNotFoundException cnfe) {
329                            }
330                    }
331            }
332    
333    }