1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.component.util

File ReflectionUtils.java

 

Coverage histogram

../../../../img/srcFileCovDistChart8.png
54% of files have more coverage

Code metrics

92
188
20
1
589
342
76
0.4
9.4
20
3.8

Classes

Class Line # Actions
ReflectionUtils 45 188 0% 76 63
0.7979%
 

Contributing tests

This file is covered by 3356 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.component.util;
21   
22    import java.lang.annotation.Annotation;
23    import java.lang.reflect.AnnotatedElement;
24    import java.lang.reflect.Array;
25    import java.lang.reflect.Field;
26    import java.lang.reflect.GenericArrayType;
27    import java.lang.reflect.ParameterizedType;
28    import java.lang.reflect.Type;
29    import java.lang.reflect.TypeVariable;
30    import java.util.ArrayList;
31    import java.util.Collection;
32    import java.util.Collections;
33    import java.util.HashMap;
34    import java.util.LinkedHashMap;
35    import java.util.LinkedList;
36    import java.util.List;
37    import java.util.Map;
38   
39    /**
40    * Various Reflection utilities.
41    *
42    * @version $Id: 5df2916cb04481fb437bf639fa35f8eae192956c $
43    * @since 2.1RC1
44    */
 
45    public final class ReflectionUtils
46    {
47    /**
48    * Utility class.
49    */
 
50  0 toggle private ReflectionUtils()
51    {
52    // Utility class
53    }
54   
55    /**
56    * @param clazz the class for which to return all fields
57    * @return all fields declared by the passed class and its superclasses
58    */
 
59  742094 toggle public static Collection<Field> getAllFields(Class<?> clazz)
60    {
61    // Note: use a linked hash map to keep the same order as the one used to declare the fields.
62  742094 Map<String, Field> fields = new LinkedHashMap<String, Field>();
63  742094 Class<?> targetClass = clazz;
64  2904583 while (targetClass != null) {
65  2162489 Field[] targetClassFields;
66  2162489 try {
67  2162489 targetClassFields = targetClass.getDeclaredFields();
68    } catch (NoClassDefFoundError e) {
69    // Provide a better exception message to more easily debug component loading issue.
70    // Specifically with this error message we'll known which component failed to be initialized.
71  0 throw new NoClassDefFoundError("Failed to get fields for class [" + targetClass.getName()
72    + "] because the class [" + e.getMessage() + "] couldn't be found in the ClassLoader.");
73    }
74   
75  2162489 for (Field field : targetClassFields) {
76    // Make sure that if the same field is declared in a class and its superclass
77    // only the field used in the class will be returned. Note that we need to do
78    // this check since the Field object doesn't implement the equals method using
79    // the field name.
80  4755205 if (!field.isSynthetic() && !fields.containsKey(field.getName())) {
81  4075803 fields.put(field.getName(), field);
82    }
83    }
84  2162489 targetClass = targetClass.getSuperclass();
85    }
86  742094 return fields.values();
87    }
88   
89    /**
90    * @param clazz the class for which to return all fields
91    * @param fieldName the name of the field to get
92    * @return the field specified from either the passed class or its superclasses
93    * @exception NoSuchFieldException if the field doesn't exist in the class or superclasses
94    */
 
95  8 toggle public static Field getField(Class<?> clazz, String fieldName) throws NoSuchFieldException
96    {
97  8 Field resultField = null;
98  8 Class<?> targetClass = clazz;
99  12 while (targetClass != null) {
100  11 try {
101  11 resultField = targetClass.getDeclaredField(fieldName);
102  7 break;
103    } catch (NoSuchFieldException e) {
104    // Look in superclass
105  4 targetClass = targetClass.getSuperclass();
106    }
107    }
108   
109  8 if (resultField == null) {
110  1 throw new NoSuchFieldException("No field named [" + fieldName + "] in class [" + clazz.getName()
111    + "] or superclasses");
112    }
113   
114  7 return resultField;
115    }
116   
117    /**
118    * Extract the main class from the passed {@link Type}.
119    *
120    * @param type the generic {@link Type}
121    * @return the main Class of the generic {@link Type}
122    * @since 4.0M1
123    */
 
124  1138297 toggle public static Class getTypeClass(Type type)
125    {
126  1138285 Class typeClassClass = null;
127   
128  1138281 if (type instanceof Class) {
129  620777 typeClassClass = (Class) type;
130  517498 } else if (type instanceof ParameterizedType) {
131  516783 typeClassClass = (Class) ((ParameterizedType) type).getRawType();
132  685 } else if (type instanceof GenericArrayType) {
133  0 Class<?> arrrayParameter = getTypeClass(((GenericArrayType) type).getGenericComponentType());
134  0 if (arrrayParameter != null) {
135  0 typeClassClass = Array.newInstance(arrrayParameter, 0).getClass();
136    }
137    }
138   
139  1138310 return typeClassClass;
140    }
141   
142    /**
143    * Sets a value to a field using reflection even if the field is private.
144    *
145    * @param instanceContainingField the object containing the field
146    * @param fieldName the name of the field in the object
147    * @param fieldValue the value to set for the provided field
148    */
 
149  709112 toggle public static void setFieldValue(Object instanceContainingField, String fieldName, Object fieldValue)
150    {
151    // Find the class containing the field to set
152  709111 Class<?> targetClass = instanceContainingField.getClass();
153  967928 while (targetClass != null) {
154  967922 for (Field field : targetClass.getDeclaredFields()) {
155  3945817 if (field.getName().equalsIgnoreCase(fieldName)) {
156  709100 try {
157  709100 boolean isAccessible = field.isAccessible();
158  709103 try {
159  709103 field.setAccessible(true);
160  709099 field.set(instanceContainingField, fieldValue);
161    } finally {
162  709090 field.setAccessible(isAccessible);
163    }
164    } catch (Exception e) {
165    // This shouldn't happen but if it does then the Component manager will not function properly
166    // and we need to abort. It probably means the Java security manager has been configured to
167    // prevent accessing private fields.
168  0 throw new RuntimeException("Failed to set field [" + fieldName + "] in instance of ["
169    + instanceContainingField.getClass().getName() + "]. The Java Security Manager has "
170    + "probably been configured to prevent settting private field values. XWiki requires "
171    + "this ability to work.", e);
172    }
173  709092 return;
174    }
175    }
176  258817 targetClass = targetClass.getSuperclass();
177    }
178    }
179   
180    /**
181    * Extract the last generic type from the passed field. For example <tt>private List&lt;A, B&gt; field</tt> would
182    * return the {@code B} class.
183    *
184    * @param field the field from which to extract the generic type
185    * @return the class of the last generic type or null if the field doesn't have a generic type
186    */
 
187  0 toggle public static Class<?> getLastGenericFieldType(Field field)
188    {
189  0 return getTypeClass(getLastFieldGenericArgument(field));
190    }
191   
192    /**
193    * Extract the last generic type from the passed field. For example <tt>private List&lt;A, B&gt; field</tt> would
194    * return the {@code B} class.
195    *
196    * @param field the field from which to extract the generic type
197    * @return the type of the last generic type or null if the field doesn't have a generic type
198    * @since 4.0M1
199    */
 
200  0 toggle public static Type getLastFieldGenericArgument(Field field)
201    {
202  0 return getLastTypeGenericArgument(field.getGenericType());
203    }
204   
205    /**
206    * Extract the last generic type from the passed Type. For example <tt>private List&lt;A, B&gt; field</tt> would
207    * return the {@code B} class.
208    *
209    * @param type the type from which to extract the generic type
210    * @return the type of the last generic type or null if the field doesn't have a generic type
211    * @since 4.0M1
212    */
 
213  52220 toggle public static Type getLastTypeGenericArgument(Type type)
214    {
215  52227 if (type instanceof ParameterizedType) {
216  52224 ParameterizedType pType = (ParameterizedType) type;
217  52221 Type[] types = pType.getActualTypeArguments();
218  52223 if (types.length > 0) {
219  52217 return types[types.length - 1];
220    }
221    }
222   
223  0 return null;
224    }
225   
226    /**
227    * Extract the last generic type from the passed class. For example
228    * <tt>public Class MyClass implements FilterClass&lt;A, B&gt;, SomeOtherClass&lt;C&gt;</tt> will return {@code B}.
229    *
230    * @param clazz the class to extract from
231    * @param filterClass the class of the generic type we're looking for
232    * @return the last generic type from the interfaces of the passed class, filtered by the passed filter class
233    */
 
234  0 toggle public static Class<?> getLastGenericClassType(Class clazz, Class filterClass)
235    {
236  0 Type type = getGenericClassType(clazz, filterClass);
237   
238  0 if (type instanceof ParameterizedType) {
239  0 ParameterizedType pType = (ParameterizedType) type;
240  0 if (filterClass.isAssignableFrom((Class) pType.getRawType())) {
241  0 Type[] actualTypes = pType.getActualTypeArguments();
242  0 if (actualTypes.length > 0 && actualTypes[actualTypes.length - 1] instanceof Class) {
243  0 return (Class) actualTypes[actualTypes.length - 1];
244    }
245    }
246    }
247   
248  0 return null;
249    }
250   
251    /**
252    * Extract the real Type from the passed class. For example
253    * <tt>public Class MyClass implements FilterClass&lt;A, B&gt;, SomeOtherClass&lt;C&gt;</tt> will return
254    * <tt>FilterClass&lt;A, B&gt;, SomeOtherClass&lt;C&gt;</tt>.
255    *
256    * @param clazz the class to extract from
257    * @param filterClass the class of the generic type we're looking for
258    * @return the real Type from the interfaces of the passed class, filtered by the passed filter class
259    * @since 4.0M1
260    */
 
261  0 toggle public static Type getGenericClassType(Class clazz, Class filterClass)
262    {
263  0 for (Type type : clazz.getGenericInterfaces()) {
264  0 if (type == filterClass) {
265  0 return type;
266  0 } else if (type instanceof ParameterizedType) {
267  0 ParameterizedType pType = (ParameterizedType) type;
268  0 if (filterClass.isAssignableFrom((Class) pType.getRawType())) {
269  0 return type;
270    }
271    }
272    }
273   
274  0 return null;
275    }
276   
277    /**
278    * @param parameters the parameters of a direct superclass or interface
279    * @param childType a extending class as Type
280    * @return the actual parameters of the direct superclass or interface, return null if it's impossible to resolve
281    */
 
282  0 toggle public static Type[] resolveSuperArguments(Type[] parameters, Type childType)
283    {
284  0 Type[] resolvedPrameters = null;
285   
286  0 if (parameters != null && childType instanceof ParameterizedType) {
287  0 ParameterizedType parameterizedChildType = (ParameterizedType) childType;
288   
289  0 return resolveSuperArguments(parameters, parameterizedChildType.getClass(),
290    parameterizedChildType.getActualTypeArguments());
291    }
292   
293  0 return resolvedPrameters;
294    }
295   
296    /**
297    * @param parameters the parameters of a direct superclass or interface
298    * @param childClass an extending class
299    * @param childParameters the actual parameters of the extending class
300    * @return the actual parameters of the direct superclass or interface, return null if it's impossible to resolve
301    */
 
302  357757 toggle public static Type[] resolveSuperArguments(Type[] parameters, Class childClass, Type[] childParameters)
303    {
304  357758 Map<TypeVariable, Type> typeMapping;
305  357757 if (childParameters != null) {
306  154309 TypeVariable<Class>[] declaredChildParameters = childClass.getTypeParameters();
307   
308  154309 typeMapping = new HashMap<TypeVariable, Type>();
309  352023 for (int i = 0; i < declaredChildParameters.length; ++i) {
310  197714 typeMapping.put(declaredChildParameters[i], childParameters[i]);
311    }
312    } else {
313  203450 typeMapping = Collections.emptyMap();
314    }
315   
316  357757 return resolveTypes(parameters, typeMapping);
317    }
318   
319    /**
320    * @param type the type to resolve
321    * @param typeMapping the mapping between TypeVariable and real type
322    * @return the resolved type, the passed type it does not need to be resolved or null if it can't be resolved
323    */
 
324  427263 toggle public static Type resolveType(Type type, Map<TypeVariable, Type> typeMapping)
325    {
326  427262 Type resolvedType = type;
327   
328  427264 if (type instanceof TypeVariable) {
329  165481 if (typeMapping == null) {
330  0 return null;
331    }
332   
333  165481 resolvedType = typeMapping.get(type);
334  261784 } else if (type instanceof ParameterizedType) {
335  17442 ParameterizedType parameterizedType = (ParameterizedType) type;
336   
337  17442 Type[] arguments = parameterizedType.getActualTypeArguments();
338  17442 Type[] resolvedArguments = resolveTypes(arguments, typeMapping);
339   
340  17442 if (resolvedArguments != arguments) {
341  2268 resolvedType =
342    new DefaultParameterizedType(parameterizedType.getOwnerType(),
343    (Class<?>) parameterizedType.getRawType(), resolvedArguments);
344    } else {
345  15174 resolvedType = type;
346    }
347    }
348   
349  427264 return resolvedType;
350    }
351   
352    /**
353    * @param types the types to resolve
354    * @param typeMapping the mapping between TypeVariable and real type
355    * @return the resolved types, the passed types if nothing need to be resolved or null if it can't be fully resolved
356    */
 
357  375200 toggle private static Type[] resolveTypes(Type[] types, Map<TypeVariable, Type> typeMapping)
358    {
359  375200 Type[] resolvedTypes = types;
360   
361  800652 for (int i = 0; i < types.length; ++i) {
362  427263 Type type = types[i];
363  427264 Type resovedType = resolveType(type, typeMapping);
364   
365  427263 if (resovedType == null) {
366  1813 return null;
367    }
368   
369  425451 if (resovedType != type) {
370  165936 if (resolvedTypes == types) {
371  147081 resolvedTypes = new Type[types.length];
372  147098 for (int j = 0; j < i; ++j) {
373  17 resolvedTypes[j] = types[j];
374    }
375    }
376    }
377   
378  425452 if (resolvedTypes != types) {
379  165937 resolvedTypes[i] = resovedType;
380    }
381    }
382   
383  373387 return resolvedTypes;
384    }
385   
386    /**
387    * Find and replace the generic parameters with the real types.
388    *
389    * @param targetType the type for which to resolve the parameters
390    * @param rootType an extending class as Type
391    * @return the Type with resolved parameters
392    */
 
393  36125 toggle public static Type resolveType(Type targetType, Type rootType)
394    {
395  36126 Type resolvedType;
396   
397  36126 if (targetType instanceof ParameterizedType && rootType instanceof ParameterizedType) {
398  0 ParameterizedType parameterizedType = (ParameterizedType) targetType;
399   
400  0 resolvedType =
401    resolveType((Class<?>) parameterizedType.getRawType(), parameterizedType.getActualTypeArguments(),
402    getTypeClass(rootType));
403    } else {
404  36127 resolvedType = resolveType(getTypeClass(rootType), null, getTypeClass(targetType));
405    }
406   
407  36125 return resolvedType;
408    }
409   
410    /**
411    * Find the real generic parameters of the passed target class from the extending/implementing root class and create
412    * a Type from it.
413    *
414    * @param rootClass the root class from which to start searching
415    * @param parameters the parameters of the root class
416    * @param targetClass the class from which to resolve the generic parameters
417    * @return a {@link ParameterizedType} version of the passed target class with resolved parameters
418    */
 
419  78170 toggle private static Type resolveType(Class<?> rootClass, Type[] parameters, Class<?> targetClass)
420    {
421    // Look at super interfaces
422  78169 for (Type interfaceType : rootClass.getGenericInterfaces()) {
423  62483 Type type = resolveType(interfaceType, rootClass, parameters, targetClass);
424  62487 if (type != null) {
425  21526 return type;
426    }
427    }
428   
429  56639 Type superType = rootClass.getGenericSuperclass();
430  56641 if (superType != null) {
431  15682 return resolveType(superType, rootClass, parameters, targetClass);
432    }
433   
434  40960 return null;
435    }
436   
437    /**
438    * @param superType the type implemented/extended by the root class
439    * @param rootClass the class containing the parameters
440    * @param parameters the generic parameters
441    * @param targetClass the target class
442    * @return the passed type with the real parameters
443    */
 
444  78164 toggle private static Type resolveType(Type superType, Class<?> rootClass, Type[] parameters, Class<?> targetClass)
445    {
446  78164 Type newType = superType;
447   
448  78165 Class<?> interfaceClass;
449  78165 Type[] interfaceParameters;
450   
451  78167 if (newType instanceof ParameterizedType) {
452  16727 ParameterizedType interfaceParameterizedType = (ParameterizedType) newType;
453   
454  16728 interfaceClass = ReflectionUtils.getTypeClass(newType);
455  16729 Type[] variableParameters = interfaceParameterizedType.getActualTypeArguments();
456   
457  16729 interfaceParameters = ReflectionUtils.resolveSuperArguments(variableParameters, rootClass, parameters);
458   
459  16729 if (interfaceParameters == null) {
460  1030 newType = interfaceClass;
461  15697 } else if (interfaceParameters != variableParameters) {
462  2447 newType =
463    new DefaultParameterizedType(interfaceParameterizedType.getOwnerType(), interfaceClass,
464    interfaceParameters);
465    }
466  61442 } else if (newType instanceof Class) {
467  61441 interfaceClass = (Class<?>) newType;
468  61442 interfaceParameters = null;
469    } else {
470  0 return null;
471    }
472   
473  78171 if (interfaceClass == targetClass) {
474  36127 return newType;
475    }
476   
477  42044 return resolveType(interfaceClass, interfaceParameters, targetClass);
478    }
479   
480    /**
481    * Retrieve a {@link Type} object from it's serialized form.
482    *
483    * @param serializedType the serialized form of the {@link Type} to retrieve
484    * @param classLoader the {@link ClassLoader} to look into to find the given {@link Type}
485    * @return the type built from the given {@link String}
486    * @throws ClassNotFoundException if no class corresponding to the passed serialized type can be found
487    */
 
488  24 toggle public static Type unserializeType(String serializedType, ClassLoader classLoader) throws ClassNotFoundException
489    {
490  24 String sType = serializedType.replaceAll(" ", "");
491  24 String inferior = "<";
492  24 Type type = null;
493   
494    // A real parser could be used here but it would probably be overkill.
495  24 if (sType.contains(inferior)) {
496    // Parameterized type
497  9 int firstInferior = sType.indexOf(inferior);
498  9 int lastSuperior = sType.lastIndexOf(">");
499  9 String rawType = sType.substring(0, firstInferior);
500  9 String sArguments = sType.substring(firstInferior + 1, lastSuperior);
501  9 List<Type> argumentTypes = new ArrayList<Type>();
502  9 int nestedArgsDepth = 0;
503  9 int previousSplit = 0;
504    // We'll go through all the Type arguments and they will be unserialized, since arguments can be
505    // ParameterizedTypes themselves we need to avoid parsing their arguments, that's why we need the
506    // nestedArgsDepth counter.
507  447 for (int i = 0; i < sArguments.length(); i++) {
508  438 char current = sArguments.charAt(i);
509  438 switch (current) {
510  4 case '<':
511  4 nestedArgsDepth++;
512  4 break;
513  4 case '>':
514  4 nestedArgsDepth--;
515  4 break;
516  5 case ',':
517  5 if (nestedArgsDepth == 0) {
518  4 argumentTypes.add(unserializeType(sArguments.substring(previousSplit, i), classLoader));
519  4 previousSplit = i + 1;
520    }
521  5 break;
522  425 default:
523  425 break;
524    }
525  438 if (i == sArguments.length() - 1) {
526    // We're at the end of the parameter list, we need to unserialize the Type of the last element.
527    // If there was only one argument it will be unserialized here.
528  9 argumentTypes.add(unserializeType(sArguments.substring(previousSplit), classLoader));
529    }
530    }
531   
532  9 type =
533    new DefaultParameterizedType(null, Class.forName(rawType, false, classLoader),
534    argumentTypes.toArray(new Type[1]));
535    } else {
536    // This was a simple type, no type arguments were found.
537  15 type = Class.forName(sType, false, classLoader);
538    }
539   
540  23 return type;
541    }
542   
543    /**
544    * Get the first found annotation with the provided class directly assigned to the provided {@link AnnotatedElement}
545    * .
546    *
547    * @param <T> the type of the annotation
548    * @param annotationClass the annotation class
549    * @param element the class on which annotation are assigned
550    * @return the found annotation or null if there is none
551    */
 
552  4406686 toggle public static <T extends Annotation> T getDirectAnnotation(Class<T> annotationClass, AnnotatedElement element)
553    {
554    // Handle interfaces directly declared in the passed component class
555  4406681 for (Annotation annotation : element.getDeclaredAnnotations()) {
556  2755615 if (annotation.annotationType() == annotationClass) {
557  711795 return (T) annotation;
558    }
559    }
560   
561  3694882 return null;
562    }
563   
564    /**
565    * @param type the type from which to extract super type and interfaces
566    * @return the direct super type and interfaces for the provided type
567    */
 
568  18542 toggle public static List<Type> getDirectTypes(Type type)
569    {
570  18542 Class<?> clazz = getTypeClass(type);
571   
572  18542 if (clazz == null) {
573  0 return Collections.emptyList();
574    }
575   
576  18542 List<Type> types = new LinkedList<Type>();
577   
578  18542 for (Type interfaceType : clazz.getGenericInterfaces()) {
579  21521 types.add(resolveType(interfaceType, type));
580    }
581   
582  18542 Type superType = clazz.getGenericSuperclass();
583  18542 if (superType != null) {
584  8524 types.add(resolveType(superType, type));
585    }
586   
587  18542 return types;
588    }
589    }