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    
022    import java.util.Arrays;
023    import java.util.List;
024    
025    /**
026     * @author Brian Wing Shun Chan
027     * @author Miguel Pastor
028     * @author Shuyang Zhou
029     */
030    public class ReflectionUtil {
031    
032            public static Class<?> getAnnotationDeclaringClass(
033                    Class<? extends Annotation> annotationClass, Class<?> clazz) {
034    
035                    if ((clazz == null) || clazz.equals(Object.class)) {
036                            return null;
037                    }
038    
039                    if (isAnnotationDeclaredInClass(annotationClass, clazz)) {
040                            return clazz;
041                    }
042                    else {
043                            return getAnnotationDeclaringClass(
044                                    annotationClass, clazz.getSuperclass());
045                    }
046            }
047    
048            public static Method getBridgeMethod(
049                            Class<?> clazz, String name, Class<?> ... parameterTypes)
050                    throws Exception {
051    
052                    Method method = clazz.getMethod(name, parameterTypes);
053    
054                    if (method.isBridge()) {
055                            return method;
056                    }
057    
058                    bridge:
059                    for (Method currentMethod : clazz.getMethods()) {
060                            if (!currentMethod.isBridge() ||
061                                    name.equals(currentMethod.getName())) {
062    
063                                    continue;
064                            }
065    
066                            Class<?>[] currentParameterTypes =
067                                    currentMethod.getParameterTypes();
068    
069                            if (currentParameterTypes.length != parameterTypes.length) {
070                                    continue;
071                            }
072    
073                            for (int i = 0; i < currentParameterTypes.length; i++) {
074                                    if (!currentParameterTypes[i].isAssignableFrom(
075                                                    parameterTypes[i])) {
076    
077                                            continue bridge;
078                                    }
079                            }
080    
081                            return currentMethod;
082                    }
083    
084                    throw new NoSuchMethodException(
085                            "No bridge method on " + clazz + " with name " + name +
086                                    " and parameter types " + Arrays.toString(parameterTypes));
087            }
088    
089            public static Field getDeclaredField(Class<?> clazz, String name)
090                    throws Exception {
091    
092                    Field field = clazz.getDeclaredField(name);
093    
094                    if (!field.isAccessible()) {
095                            field.setAccessible(true);
096                    }
097    
098                    return field;
099            }
100    
101            public static Method getDeclaredMethod(
102                            Class<?> clazz, String name, Class<?> ... parameterTypes)
103                    throws Exception {
104    
105                    Method method = clazz.getDeclaredMethod(name, parameterTypes);
106    
107                    if (!method.isAccessible()) {
108                            method.setAccessible(true);
109                    }
110    
111                    return method;
112            }
113    
114            public static Class<?>[] getInterfaces(Object object) {
115                    return getInterfaces(object, null);
116            }
117    
118            public static Class<?>[] getInterfaces(
119                    Object object, ClassLoader classLoader) {
120    
121                    List<Class<?>> interfaceClasses = new UniqueList<Class<?>>();
122    
123                    Class<?> clazz = object.getClass();
124    
125                    _getInterfaces(interfaceClasses, clazz, classLoader);
126    
127                    Class<?> superClass = clazz.getSuperclass();
128    
129                    while (superClass != null) {
130                            _getInterfaces(interfaceClasses, superClass, classLoader);
131    
132                            superClass = superClass.getSuperclass();
133                    }
134    
135                    return interfaceClasses.toArray(new Class<?>[interfaceClasses.size()]);
136            }
137    
138            public static Class<?>[] getParameterTypes(Object[] arguments) {
139                    if (arguments == null) {
140                            return null;
141                    }
142    
143                    Class<?>[] parameterTypes = new Class<?>[arguments.length];
144    
145                    for (int i = 0; i < arguments.length; i++) {
146                            if (arguments[i] == null) {
147                                    parameterTypes[i] = null;
148                            }
149                            else if (arguments[i] instanceof Boolean) {
150                                    parameterTypes[i] = Boolean.TYPE;
151                            }
152                            else if (arguments[i] instanceof Byte) {
153                                    parameterTypes[i] = Byte.TYPE;
154                            }
155                            else if (arguments[i] instanceof Character) {
156                                    parameterTypes[i] = Character.TYPE;
157                            }
158                            else if (arguments[i] instanceof Double) {
159                                    parameterTypes[i] = Double.TYPE;
160                            }
161                            else if (arguments[i] instanceof Float) {
162                                    parameterTypes[i] = Float.TYPE;
163                            }
164                            else if (arguments[i] instanceof Integer) {
165                                    parameterTypes[i] = Integer.TYPE;
166                            }
167                            else if (arguments[i] instanceof Long) {
168                                    parameterTypes[i] = Long.TYPE;
169                            }
170                            else if (arguments[i] instanceof Short) {
171                                    parameterTypes[i] = Short.TYPE;
172                            }
173                            else {
174                                    parameterTypes[i] = arguments[i].getClass();
175                            }
176                    }
177    
178                    return parameterTypes;
179            }
180    
181            public static boolean isAnnotationDeclaredInClass(
182                    Class<? extends Annotation> annotationClass, Class<?> clazz) {
183    
184                    if ((annotationClass == null) || (clazz == null)) {
185                            throw new IllegalArgumentException();
186                    }
187    
188                    Annotation[] annotations = clazz.getAnnotations();
189    
190                    for (Annotation annotation : annotations) {
191                            if (annotationClass.equals(annotation.annotationType())) {
192                                    return true;
193                            }
194                    }
195    
196                    return false;
197            }
198    
199            public static <T extends Enum<T>> T newEnumElement(
200                            Class<T> enumClass, Class<?>[] constructorParameterTypes,
201                            String name, int ordinal, Object... constructorParameters)
202                    throws Exception {
203    
204                    Class<?>[] parameterTypes = null;
205    
206                    if ((constructorParameterTypes != null) &&
207                            (constructorParameterTypes.length != 0)) {
208    
209                            parameterTypes = new Class<?>[constructorParameterTypes.length + 2];
210    
211                            parameterTypes[0] = String.class;
212                            parameterTypes[1] = int.class;
213    
214                            System.arraycopy(
215                                    constructorParameterTypes, 0, parameterTypes, 2,
216                                    constructorParameterTypes.length);
217                    }
218                    else {
219                            parameterTypes = new Class<?>[2];
220    
221                            parameterTypes[0] = String.class;
222                            parameterTypes[1] = int.class;
223                    }
224    
225                    Constructor<T> constructor = enumClass.getDeclaredConstructor(
226                            parameterTypes);
227    
228                    Method acquireConstructorAccessorMethod = getDeclaredMethod(
229                            Constructor.class, "acquireConstructorAccessor");
230    
231                    acquireConstructorAccessorMethod.invoke(constructor);
232    
233                    Field constructorAccessorField = getDeclaredField(
234                            Constructor.class, "constructorAccessor");
235    
236                    Object constructorAccessor = constructorAccessorField.get(constructor);
237    
238                    Method newInstanceMethod = getDeclaredMethod(
239                            constructorAccessor.getClass(), "newInstance", Object[].class);
240    
241                    Object[] parameters = null;
242    
243                    if ((constructorParameters != null) &&
244                            (constructorParameters.length != 0)) {
245    
246                            parameters = new Object[constructorParameters.length + 2];
247    
248                            parameters[0] = name;
249                            parameters[1] = ordinal;
250    
251                            System.arraycopy(
252                                    constructorParameters, 0, parameters, 2,
253                                    constructorParameters.length);
254    
255                    }
256                    else {
257                            parameters = new Object[2];
258    
259                            parameters[0] = name;
260                            parameters[1] = ordinal;
261                    }
262    
263                    return (T)newInstanceMethod.invoke(
264                            constructorAccessor, new Object[]{parameters});
265            }
266    
267            public static <T extends Enum<T>> T newEnumElement(
268                            Class<T> enumClass, String name, int ordinal)
269                    throws Exception {
270    
271                    return newEnumElement(enumClass, null, name, ordinal, (Object[])null);
272            }
273    
274            private static void _getInterfaces(
275                    List<Class<?>> interfaceClasses, Class<?> clazz,
276                    ClassLoader classLoader) {
277    
278                    for (Class<?> interfaceClass : clazz.getInterfaces()) {
279                            try {
280                                    if (classLoader != null) {
281                                            interfaceClasses.add(
282                                                    classLoader.loadClass(interfaceClass.getName()));
283                                    }
284                                    else {
285                                            interfaceClasses.add(interfaceClass);
286                                    }
287                            }
288                            catch (ClassNotFoundException cnfe) {
289                            }
290                    }
291            }
292    
293    }