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.test;
016    
017    import com.liferay.portal.kernel.util.ReflectionUtil;
018    
019    import java.lang.reflect.Constructor;
020    import java.lang.reflect.Field;
021    import java.lang.reflect.Method;
022    
023    import java.util.Arrays;
024    
025    /**
026     * @author Shuyang Zhou
027     */
028    public class ReflectionTestUtil {
029    
030            public static Method getBridgeMethod(
031                    Class<?> clazz, String methodName, Class<?>... parameterTypes) {
032    
033                    Method method = getMethod(clazz, methodName, parameterTypes);
034    
035                    if (method.isBridge()) {
036                            return method;
037                    }
038    
039                    Method bridgeMethod = _findBridgeMethod(clazz.getMethods(), method);
040    
041                    if (bridgeMethod != null) {
042                            return bridgeMethod;
043                    }
044    
045                    while (clazz != null) {
046                            bridgeMethod = _findBridgeMethod(
047                                    clazz.getDeclaredMethods(), method);
048    
049                            if (bridgeMethod != null) {
050                                    return bridgeMethod;
051                            }
052    
053                            clazz =  clazz.getSuperclass();
054                    }
055    
056                    return ReflectionUtil.throwException(
057                            new NoSuchMethodException(
058                                    "No bridge method on " + clazz + " with name " + methodName +
059                                            " and parameter types " + Arrays.toString(parameterTypes)));
060            }
061    
062            public static Field getField(Class<?> clazz, String fieldName) {
063                    try {
064                            Field field = clazz.getField(fieldName);
065    
066                            field.setAccessible(true);
067    
068                            ReflectionUtil.unfinalField(field);
069    
070                            return field;
071                    }
072                    catch (NoSuchFieldException nsfe) {
073                    }
074                    catch (Exception e) {
075                            return ReflectionUtil.throwException(e);
076                    }
077    
078                    while (clazz != null) {
079                            try {
080                                    Field field = clazz.getDeclaredField(fieldName);
081    
082                                    field.setAccessible(true);
083    
084                                    ReflectionUtil.unfinalField(field);
085    
086                                    return field;
087                            }
088                            catch (NoSuchFieldException nsfe) {
089                                    clazz = clazz.getSuperclass();
090                            }
091                            catch (Exception e) {
092                                    return ReflectionUtil.throwException(e);
093                            }
094                    }
095    
096                    return ReflectionUtil.throwException(
097                            new NoSuchFieldException(
098                                    "No field on " + clazz + " with name " + fieldName));
099            }
100    
101            public static <T> T getFieldValue(Class<?> clazz, String fieldName) {
102                    Field field = getField(clazz, fieldName);
103    
104                    try {
105                            return (T)field.get(null);
106                    }
107                    catch (Exception e) {
108                            return ReflectionUtil.throwException(e);
109                    }
110            }
111    
112            public static <T> T getFieldValue(Object instance, String fieldName) {
113                    Field field = getField(instance.getClass(), fieldName);
114    
115                    try {
116                            return (T)field.get(instance);
117                    }
118                    catch (Exception e) {
119                            return ReflectionUtil.throwException(e);
120                    }
121            }
122    
123            public static Method getMethod(
124                    Class<?> clazz, String methodName, Class<?>... parameterTypes) {
125    
126                    try {
127                            Method method = clazz.getMethod(methodName, parameterTypes);
128    
129                            method.setAccessible(true);
130    
131                            return method;
132                    }
133                    catch (NoSuchMethodException nsme) {
134                    }
135    
136                    while (clazz != null) {
137                            try {
138                                    Method method = clazz.getDeclaredMethod(
139                                            methodName, parameterTypes);
140    
141                                    method.setAccessible(true);
142    
143                                    return method;
144                            }
145                            catch (NoSuchMethodException nsme) {
146                                    clazz = clazz.getSuperclass();
147                            }
148                    }
149    
150                    return ReflectionUtil.throwException(
151                            new NoSuchMethodException(
152                                    "No method on " + clazz + " with name " + methodName +
153                                            " and parameter types " + Arrays.toString(parameterTypes)));
154            }
155    
156            public static <T> T invoke(
157                    Class<?> clazz, String methodName, Class<?>[] parameterTypes,
158                    Object... parameters) {
159    
160                    Method method = getMethod(clazz, methodName, parameterTypes);
161    
162                    try {
163                            return (T)method.invoke(null, parameters);
164                    }
165                    catch (Exception e) {
166                            return ReflectionUtil.throwException(e);
167                    }
168            }
169    
170            public static <T> T invoke(
171                    Object instance, String methodName, Class<?>[] parameterTypes,
172                    Object... parameters) {
173    
174                    Method method = getMethod(
175                            instance.getClass(), methodName, parameterTypes);
176    
177                    try {
178                            return (T)method.invoke(instance, parameters);
179                    }
180                    catch (Exception e) {
181                            return ReflectionUtil.throwException(e);
182                    }
183            }
184    
185            public static <T> T invokeBridge(
186                    Object instance, String methodName, Class<?>[] parameterTypes,
187                    Object... parameters) {
188    
189                    Method method = getBridgeMethod(
190                            instance.getClass(), methodName, parameterTypes);
191    
192                    try {
193                            return (T)method.invoke(instance, parameters);
194                    }
195                    catch (Exception e) {
196                            return ReflectionUtil.throwException(e);
197                    }
198            }
199    
200            public static <T extends Enum<T>> T newEnumElement(
201                    Class<T> enumClass, Class<?>[] constructorParameterTypes, String name,
202                    int ordinal, Object... constructorParameters) {
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                    try {
226                            Constructor<T> constructor = enumClass.getDeclaredConstructor(
227                                    parameterTypes);
228    
229                            Method acquireConstructorAccessorMethod =
230                                    ReflectionUtil.getDeclaredMethod(
231                                            Constructor.class, "acquireConstructorAccessor");
232    
233                            acquireConstructorAccessorMethod.invoke(constructor);
234    
235                            Field constructorAccessorField = ReflectionUtil.getDeclaredField(
236                                    Constructor.class, "constructorAccessor");
237    
238                            Object constructorAccessor = constructorAccessorField.get(
239                                    constructor);
240    
241                            Method newInstanceMethod = ReflectionUtil.getDeclaredMethod(
242                                    constructorAccessor.getClass(), "newInstance", Object[].class);
243    
244                            Object[] parameters = null;
245    
246                            if ((constructorParameters != null) &&
247                                    (constructorParameters.length != 0)) {
248    
249                                    parameters = new Object[constructorParameters.length + 2];
250    
251                                    parameters[0] = name;
252                                    parameters[1] = ordinal;
253    
254                                    System.arraycopy(
255                                            constructorParameters, 0, parameters, 2,
256                                            constructorParameters.length);
257                            }
258                            else {
259                                    parameters = new Object[2];
260    
261                                    parameters[0] = name;
262                                    parameters[1] = ordinal;
263                            }
264    
265                            return (T)newInstanceMethod.invoke(
266                                    constructorAccessor, new Object[] {parameters});
267                    }
268                    catch (Exception e) {
269                            return ReflectionUtil.throwException(e);
270                    }
271            }
272    
273            public static <T extends Enum<T>> T newEnumElement(
274                    Class<T> enumClass, String name, int ordinal) {
275    
276                    return newEnumElement(enumClass, null, name, ordinal, (Object[])null);
277            }
278    
279            public static void setFieldValue(
280                    Class<?> clazz, String fieldName, Object value) {
281    
282                    Field field = getField(clazz, fieldName);
283    
284                    try {
285                            field.set(null, value);
286                    }
287                    catch (Exception e) {
288                            ReflectionUtil.throwException(e);
289                    }
290            }
291    
292            public static void setFieldValue(
293                    Object instance, String fieldName, Object value) {
294    
295                    Field field = getField(instance.getClass(), fieldName);
296    
297                    try {
298                            field.set(instance, value);
299                    }
300                    catch (Exception e) {
301                            ReflectionUtil.throwException(e);
302                    }
303            }
304    
305            private static Method _findBridgeMethod(Method[] methods, Method method) {
306                    String name = method.getName();
307                    Class<?>[] parameterTypes = method.getParameterTypes();
308    
309                    bridge:
310                    for (Method currentMethod : methods) {
311                            if (!currentMethod.isBridge() ||
312                                    !name.equals(currentMethod.getName())) {
313    
314                                    continue;
315                            }
316    
317                            Class<?>[] currentParameterTypes =
318                                    currentMethod.getParameterTypes();
319    
320                            if (currentParameterTypes.length != parameterTypes.length) {
321                                    continue;
322                            }
323    
324                            for (int i = 0; i < currentParameterTypes.length; i++) {
325                                    if (!currentParameterTypes[i].isAssignableFrom(
326                                                    parameterTypes[i])) {
327    
328                                            continue bridge;
329                                    }
330                            }
331    
332                            currentMethod.setAccessible(true);
333    
334                            return currentMethod;
335                    }
336    
337                    return null;
338            }
339    
340    }