001    /**
002     * Copyright (c) 2000-present 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.reflect.Field;
018    import java.lang.reflect.Method;
019    import java.lang.reflect.Modifier;
020    import java.lang.reflect.ParameterizedType;
021    import java.lang.reflect.Type;
022    
023    import java.util.Arrays;
024    import java.util.HashSet;
025    import java.util.LinkedHashSet;
026    import java.util.Set;
027    
028    /**
029     * @author Brian Wing Shun Chan
030     * @author Miguel Pastor
031     * @author Shuyang Zhou
032     */
033    public class ReflectionUtil {
034    
035            public static Object arrayClone(Object array) {
036                    Class<?> clazz = array.getClass();
037    
038                    if (!clazz.isArray()) {
039                            throw new IllegalArgumentException(
040                                    "Input object is not an array: " + array);
041                    }
042    
043                    try {
044                            return _CLONE_METHOD.invoke(array);
045                    }
046                    catch (Exception e) {
047                            return throwException(e);
048                    }
049            }
050    
051            public static Field getDeclaredField(Class<?> clazz, String name)
052                    throws Exception {
053    
054                    Field field = clazz.getDeclaredField(name);
055    
056                    if (!field.isAccessible()) {
057                            field.setAccessible(true);
058                    }
059    
060                    return unfinalField(field);
061            }
062    
063            public static Method getDeclaredMethod(
064                            Class<?> clazz, String name, Class<?> ... parameterTypes)
065                    throws Exception {
066    
067                    Method method = clazz.getDeclaredMethod(name, parameterTypes);
068    
069                    if (!method.isAccessible()) {
070                            method.setAccessible(true);
071                    }
072    
073                    return method;
074            }
075    
076            public static Type getGenericInterface(
077                    Object object, Class<?> interfaceClass) {
078    
079                    Class<?> clazz = object.getClass();
080    
081                    Type genericInterface = _getGenericInterface(clazz, interfaceClass);
082    
083                    if (genericInterface != null) {
084                            return genericInterface;
085                    }
086    
087                    Class<?> superClass = clazz.getSuperclass();
088    
089                    while (superClass != null) {
090                            genericInterface = _getGenericInterface(superClass, interfaceClass);
091    
092                            if (genericInterface != null) {
093                                    return genericInterface;
094                            }
095    
096                            superClass = superClass.getSuperclass();
097                    }
098    
099                    return null;
100            }
101    
102            public static Class<?> getGenericSuperType(Class<?> clazz) {
103                    try {
104                            ParameterizedType parameterizedType =
105                                    (ParameterizedType)clazz.getGenericSuperclass();
106    
107                            Type[] types = parameterizedType.getActualTypeArguments();
108    
109                            if (types.length > 0) {
110                                    return (Class<?>)types[0];
111                            }
112                    }
113                    catch (Throwable t) {
114                    }
115    
116                    return null;
117            }
118    
119            public static Class<?>[] getInterfaces(Object object) {
120                    return getInterfaces(object, null);
121            }
122    
123            public static Class<?>[] getInterfaces(
124                    Object object, ClassLoader classLoader) {
125    
126                    Set<Class<?>> interfaceClasses = new LinkedHashSet<>();
127    
128                    Class<?> clazz = object.getClass();
129    
130                    _getInterfaces(interfaceClasses, clazz, classLoader);
131    
132                    Class<?> superClass = clazz.getSuperclass();
133    
134                    while (superClass != null) {
135                            _getInterfaces(interfaceClasses, superClass, classLoader);
136    
137                            superClass = superClass.getSuperclass();
138                    }
139    
140                    return interfaceClasses.toArray(new Class<?>[interfaceClasses.size()]);
141            }
142    
143            public static Class<?>[] getParameterTypes(Object[] arguments) {
144                    if (arguments == null) {
145                            return null;
146                    }
147    
148                    Class<?>[] parameterTypes = new Class<?>[arguments.length];
149    
150                    for (int i = 0; i < arguments.length; i++) {
151                            if (arguments[i] == null) {
152                                    parameterTypes[i] = null;
153                            }
154                            else if (arguments[i] instanceof Boolean) {
155                                    parameterTypes[i] = Boolean.TYPE;
156                            }
157                            else if (arguments[i] instanceof Byte) {
158                                    parameterTypes[i] = Byte.TYPE;
159                            }
160                            else if (arguments[i] instanceof Character) {
161                                    parameterTypes[i] = Character.TYPE;
162                            }
163                            else if (arguments[i] instanceof Double) {
164                                    parameterTypes[i] = Double.TYPE;
165                            }
166                            else if (arguments[i] instanceof Float) {
167                                    parameterTypes[i] = Float.TYPE;
168                            }
169                            else if (arguments[i] instanceof Integer) {
170                                    parameterTypes[i] = Integer.TYPE;
171                            }
172                            else if (arguments[i] instanceof Long) {
173                                    parameterTypes[i] = Long.TYPE;
174                            }
175                            else if (arguments[i] instanceof Short) {
176                                    parameterTypes[i] = Short.TYPE;
177                            }
178                            else {
179                                    parameterTypes[i] = arguments[i].getClass();
180                            }
181                    }
182    
183                    return parameterTypes;
184            }
185    
186            public static Set<Method> getVisibleMethods(Class<?> clazz) {
187                    Set<Method> visibleMethods = new HashSet<>(
188                            Arrays.asList(clazz.getMethods()));
189    
190                    visibleMethods.addAll(Arrays.asList(clazz.getDeclaredMethods()));
191    
192                    while ((clazz = clazz.getSuperclass()) != null) {
193                            for (Method method : clazz.getDeclaredMethods()) {
194                                    int modifiers = method.getModifiers();
195    
196                                    if (!Modifier.isPrivate(modifiers) &
197                                            !Modifier.isPublic(modifiers)) {
198    
199                                            visibleMethods.add(method);
200                                    }
201                            }
202                    }
203    
204                    return visibleMethods;
205            }
206    
207            public static <T> T throwException(Throwable throwable) {
208                    return ReflectionUtil.<T, RuntimeException>_doThrowException(throwable);
209            }
210    
211            public static Field unfinalField(Field field) throws Exception {
212                    int modifiers = field.getModifiers();
213    
214                    if ((modifiers & Modifier.FINAL) == Modifier.FINAL) {
215                            Field modifiersField = getDeclaredField(Field.class, "modifiers");
216    
217                            modifiersField.setInt(field, modifiers & ~Modifier.FINAL);
218                    }
219    
220                    return field;
221            }
222    
223            @SuppressWarnings("unchecked")
224            private static <T, E extends Throwable> T _doThrowException(
225                            Throwable throwable)
226                    throws E {
227    
228                    throw (E)throwable;
229            }
230    
231            private static Type _getGenericInterface(
232                    Class<?> clazz, Class<?> interfaceClass) {
233    
234                    Type[] genericInterfaces = clazz.getGenericInterfaces();
235    
236                    for (Type genericInterface : genericInterfaces) {
237                            if (!(genericInterface instanceof ParameterizedType)) {
238                                    continue;
239                            }
240    
241                            ParameterizedType parameterizedType =
242                                    (ParameterizedType)genericInterface;
243    
244                            Type rawType = parameterizedType.getRawType();
245    
246                            if (rawType.equals(interfaceClass)) {
247                                    return parameterizedType;
248                            }
249                    }
250    
251                    return null;
252            }
253    
254            private static void _getInterfaces(
255                    Set<Class<?>> interfaceClasses, Class<?> clazz,
256                    ClassLoader classLoader) {
257    
258                    for (Class<?> interfaceClass : clazz.getInterfaces()) {
259                            try {
260                                    if (classLoader != null) {
261                                            interfaceClasses.add(
262                                                    classLoader.loadClass(interfaceClass.getName()));
263                                    }
264                                    else {
265                                            interfaceClasses.add(interfaceClass);
266                                    }
267                            }
268                            catch (ClassNotFoundException cnfe) {
269                            }
270                    }
271            }
272    
273            private static final Method _CLONE_METHOD;
274    
275            static {
276                    try {
277                            _CLONE_METHOD = getDeclaredMethod(Object.class, "clone");
278                    }
279                    catch (Exception e) {
280                            throw new ExceptionInInitializerError(e);
281                    }
282            }
283    
284    }