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            public static <T> T throwException(Throwable throwable) {
257                    return ReflectionUtil.<T, RuntimeException>_doThrowException(throwable);
258            }
259    
260            public static Field unfinalField(Field field) throws Exception {
261                    int modifiers = field.getModifiers();
262    
263                    if ((modifiers & Modifier.FINAL) == Modifier.FINAL) {
264                            Field modifiersField = getDeclaredField(Field.class, "modifiers");
265    
266                            modifiersField.setInt(field, modifiers & ~Modifier.FINAL);
267                    }
268    
269                    return field;
270            }
271    
272            protected static Method getBridgeMethod(
273                            boolean publicMethod, Class<?> clazz, String name,
274                            Class<?> ... parameterTypes)
275                    throws Exception {
276    
277                    Method method = null;
278    
279                    if (publicMethod) {
280                            method = clazz.getMethod(name, parameterTypes);
281                    }
282                    else {
283                            method = clazz.getDeclaredMethod(name, parameterTypes);
284                    }
285    
286                    if (method.isBridge()) {
287                            return method;
288                    }
289    
290                    Method[] methods = null;
291    
292                    if (publicMethod) {
293                            methods = clazz.getMethods();
294                    }
295                    else {
296                            methods = clazz.getDeclaredMethods();
297                    }
298    
299                    bridge:
300                    for (Method currentMethod : methods) {
301                            if (!currentMethod.isBridge() ||
302                                    !name.equals(currentMethod.getName())) {
303    
304                                    continue;
305                            }
306    
307                            Class<?>[] currentParameterTypes =
308                                    currentMethod.getParameterTypes();
309    
310                            if (currentParameterTypes.length != parameterTypes.length) {
311                                    continue;
312                            }
313    
314                            for (int i = 0; i < currentParameterTypes.length; i++) {
315                                    if (!currentParameterTypes[i].isAssignableFrom(
316                                                    parameterTypes[i])) {
317    
318                                            continue bridge;
319                                    }
320                            }
321    
322                            return currentMethod;
323                    }
324    
325                    throw new NoSuchMethodException(
326                            "No bridge method on " + clazz + " with name " + name +
327                                    " and parameter types " + Arrays.toString(parameterTypes));
328            }
329    
330            @SuppressWarnings("unchecked")
331            private static <T, E extends Throwable> T _doThrowException(
332                            Throwable throwable)
333                    throws E {
334    
335                    throw (E)throwable;
336            }
337    
338            private static void _getInterfaces(
339                    List<Class<?>> interfaceClasses, Class<?> clazz,
340                    ClassLoader classLoader) {
341    
342                    for (Class<?> interfaceClass : clazz.getInterfaces()) {
343                            try {
344                                    if (classLoader != null) {
345                                            interfaceClasses.add(
346                                                    classLoader.loadClass(interfaceClass.getName()));
347                                    }
348                                    else {
349                                            interfaceClasses.add(interfaceClass);
350                                    }
351                            }
352                            catch (ClassNotFoundException cnfe) {
353                            }
354                    }
355            }
356    
357    }