001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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 Field[] getDeclaredFields(Class<?> clazz) throws Exception {
085                    Field[] fields = clazz.getDeclaredFields();
086    
087                    for (Field field : fields) {
088                            if (!field.isAccessible()) {
089                                    field.setAccessible(true);
090                            }
091    
092                            unfinalField(field);
093                    }
094    
095                    return fields;
096            }
097    
098            public static Method getDeclaredMethod(
099                            Class<?> clazz, String name, Class<?> ... parameterTypes)
100                    throws Exception {
101    
102                    Method method = clazz.getDeclaredMethod(name, parameterTypes);
103    
104                    if (!method.isAccessible()) {
105                            method.setAccessible(true);
106                    }
107    
108                    return method;
109            }
110    
111            public static Class<?>[] getInterfaces(Object object) {
112                    return getInterfaces(object, null);
113            }
114    
115            public static Class<?>[] getInterfaces(
116                    Object object, ClassLoader classLoader) {
117    
118                    List<Class<?>> interfaceClasses = new UniqueList<Class<?>>();
119    
120                    Class<?> clazz = object.getClass();
121    
122                    _getInterfaces(interfaceClasses, clazz, classLoader);
123    
124                    Class<?> superClass = clazz.getSuperclass();
125    
126                    while (superClass != null) {
127                            _getInterfaces(interfaceClasses, superClass, classLoader);
128    
129                            superClass = superClass.getSuperclass();
130                    }
131    
132                    return interfaceClasses.toArray(new Class<?>[interfaceClasses.size()]);
133            }
134    
135            public static Class<?>[] getParameterTypes(Object[] arguments) {
136                    if (arguments == null) {
137                            return null;
138                    }
139    
140                    Class<?>[] parameterTypes = new Class<?>[arguments.length];
141    
142                    for (int i = 0; i < arguments.length; i++) {
143                            if (arguments[i] == null) {
144                                    parameterTypes[i] = null;
145                            }
146                            else if (arguments[i] instanceof Boolean) {
147                                    parameterTypes[i] = Boolean.TYPE;
148                            }
149                            else if (arguments[i] instanceof Byte) {
150                                    parameterTypes[i] = Byte.TYPE;
151                            }
152                            else if (arguments[i] instanceof Character) {
153                                    parameterTypes[i] = Character.TYPE;
154                            }
155                            else if (arguments[i] instanceof Double) {
156                                    parameterTypes[i] = Double.TYPE;
157                            }
158                            else if (arguments[i] instanceof Float) {
159                                    parameterTypes[i] = Float.TYPE;
160                            }
161                            else if (arguments[i] instanceof Integer) {
162                                    parameterTypes[i] = Integer.TYPE;
163                            }
164                            else if (arguments[i] instanceof Long) {
165                                    parameterTypes[i] = Long.TYPE;
166                            }
167                            else if (arguments[i] instanceof Short) {
168                                    parameterTypes[i] = Short.TYPE;
169                            }
170                            else {
171                                    parameterTypes[i] = arguments[i].getClass();
172                            }
173                    }
174    
175                    return parameterTypes;
176            }
177    
178            public static boolean isAnnotationDeclaredInClass(
179                    Class<? extends Annotation> annotationClass, Class<?> clazz) {
180    
181                    if ((annotationClass == null) || (clazz == null)) {
182                            throw new IllegalArgumentException();
183                    }
184    
185                    Annotation[] annotations = clazz.getAnnotations();
186    
187                    for (Annotation annotation : annotations) {
188                            if (annotationClass.equals(annotation.annotationType())) {
189                                    return true;
190                            }
191                    }
192    
193                    return false;
194            }
195    
196            public static <T extends Enum<T>> T newEnumElement(
197                            Class<T> enumClass, Class<?>[] constructorParameterTypes,
198                            String name, int ordinal, Object... constructorParameters)
199                    throws Exception {
200    
201                    Class<?>[] parameterTypes = null;
202    
203                    if ((constructorParameterTypes != null) &&
204                            (constructorParameterTypes.length != 0)) {
205    
206                            parameterTypes = new Class<?>[constructorParameterTypes.length + 2];
207    
208                            parameterTypes[0] = String.class;
209                            parameterTypes[1] = int.class;
210    
211                            System.arraycopy(
212                                    constructorParameterTypes, 0, parameterTypes, 2,
213                                    constructorParameterTypes.length);
214                    }
215                    else {
216                            parameterTypes = new Class<?>[2];
217    
218                            parameterTypes[0] = String.class;
219                            parameterTypes[1] = int.class;
220                    }
221    
222                    Constructor<T> constructor = enumClass.getDeclaredConstructor(
223                            parameterTypes);
224    
225                    Method acquireConstructorAccessorMethod = getDeclaredMethod(
226                            Constructor.class, "acquireConstructorAccessor");
227    
228                    acquireConstructorAccessorMethod.invoke(constructor);
229    
230                    Field constructorAccessorField = getDeclaredField(
231                            Constructor.class, "constructorAccessor");
232    
233                    Object constructorAccessor = constructorAccessorField.get(constructor);
234    
235                    Method newInstanceMethod = getDeclaredMethod(
236                            constructorAccessor.getClass(), "newInstance", Object[].class);
237    
238                    Object[] parameters = null;
239    
240                    if ((constructorParameters != null) &&
241                            (constructorParameters.length != 0)) {
242    
243                            parameters = new Object[constructorParameters.length + 2];
244    
245                            parameters[0] = name;
246                            parameters[1] = ordinal;
247    
248                            System.arraycopy(
249                                    constructorParameters, 0, parameters, 2,
250                                    constructorParameters.length);
251                    }
252                    else {
253                            parameters = new Object[2];
254    
255                            parameters[0] = name;
256                            parameters[1] = ordinal;
257                    }
258    
259                    return (T)newInstanceMethod.invoke(
260                            constructorAccessor, new Object[] {parameters});
261            }
262    
263            public static <T extends Enum<T>> T newEnumElement(
264                            Class<T> enumClass, String name, int ordinal)
265                    throws Exception {
266    
267                    return newEnumElement(enumClass, null, name, ordinal, (Object[])null);
268            }
269    
270            public static <T> T throwException(Throwable throwable) {
271                    return ReflectionUtil.<T, RuntimeException>_doThrowException(throwable);
272            }
273    
274            public static Field unfinalField(Field field) throws Exception {
275                    int modifiers = field.getModifiers();
276    
277                    if ((modifiers & Modifier.FINAL) == Modifier.FINAL) {
278                            Field modifiersField = getDeclaredField(Field.class, "modifiers");
279    
280                            modifiersField.setInt(field, modifiers & ~Modifier.FINAL);
281                    }
282    
283                    return field;
284            }
285    
286            protected static Method getBridgeMethod(
287                            boolean publicMethod, Class<?> clazz, String name,
288                            Class<?> ... parameterTypes)
289                    throws Exception {
290    
291                    Method method = null;
292    
293                    if (publicMethod) {
294                            method = clazz.getMethod(name, parameterTypes);
295                    }
296                    else {
297                            method = clazz.getDeclaredMethod(name, parameterTypes);
298                    }
299    
300                    if (method.isBridge()) {
301                            return method;
302                    }
303    
304                    Method[] methods = null;
305    
306                    if (publicMethod) {
307                            methods = clazz.getMethods();
308                    }
309                    else {
310                            methods = clazz.getDeclaredMethods();
311                    }
312    
313                    bridge:
314                    for (Method currentMethod : methods) {
315                            if (!currentMethod.isBridge() ||
316                                    !name.equals(currentMethod.getName())) {
317    
318                                    continue;
319                            }
320    
321                            Class<?>[] currentParameterTypes =
322                                    currentMethod.getParameterTypes();
323    
324                            if (currentParameterTypes.length != parameterTypes.length) {
325                                    continue;
326                            }
327    
328                            for (int i = 0; i < currentParameterTypes.length; i++) {
329                                    if (!currentParameterTypes[i].isAssignableFrom(
330                                                    parameterTypes[i])) {
331    
332                                            continue bridge;
333                                    }
334                            }
335    
336                            return currentMethod;
337                    }
338    
339                    throw new NoSuchMethodException(
340                            "No bridge method on " + clazz + " with name " + name +
341                                    " and parameter types " + Arrays.toString(parameterTypes));
342            }
343    
344            @SuppressWarnings("unchecked")
345            private static <T, E extends Throwable> T _doThrowException(
346                            Throwable throwable)
347                    throws E {
348    
349                    throw (E)throwable;
350            }
351    
352            private static void _getInterfaces(
353                    List<Class<?>> interfaceClasses, Class<?> clazz,
354                    ClassLoader classLoader) {
355    
356                    for (Class<?> interfaceClass : clazz.getInterfaces()) {
357                            try {
358                                    if (classLoader != null) {
359                                            interfaceClasses.add(
360                                                    classLoader.loadClass(interfaceClass.getName()));
361                                    }
362                                    else {
363                                            interfaceClasses.add(interfaceClass);
364                                    }
365                            }
366                            catch (ClassNotFoundException cnfe) {
367                            }
368                    }
369            }
370    
371    }