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