View Javadoc
1   /*
2    * Copyright 2012-2022 Bloomreach
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.onehippo.forge.utilities.commons;
18  
19  import java.lang.annotation.Annotation;
20  import java.lang.reflect.Field;
21  import java.lang.reflect.Method;
22  import java.util.Arrays;
23  import java.util.Collection;
24  import java.util.HashMap;
25  import java.util.Iterator;
26  import java.util.Map;
27  
28  import org.slf4j.Logger;
29  import org.slf4j.LoggerFactory;
30  
31  /**
32   * Static utility class for getting (annotated) fields and methods from classes, using reflection.
33   */
34  public final class AnnotationUtil {
35  
36      private static Logger log = LoggerFactory.getLogger(AnnotationUtil.class);
37  
38      /**
39       * Private constructor preventing instantiation.
40       */
41      private AnnotationUtil() {
42      }
43  
44      /**
45       * Find a class for given name, loaded from current thread's context class loader.
46       *
47       * @param name of the class
48       * @return null if not found or Class if found
49       */
50      @SuppressWarnings({"unchecked"})
51      public static <T> Class<T> findClass(final String name) {
52          try {
53              return (Class<T>) Thread.currentThread().getContextClassLoader().loadClass(name);
54          } catch (ClassNotFoundException e) {
55              log.error("No class found within class loader " + e);
56          }
57          return null;
58      }
59  
60      /**
61       * Get fields of an class which are annotated with specific annotation and set them accessible
62       * (if necessary).
63       *
64       * @param clazz           class we are scanning for annotated fields.
65       * @param annotationClass annotation we are interested in
66       * @return a collection containing (accessible) Field objects (or an empty collection)
67       */
68      public static Collection<Field> getAnnotatedFields(final Class<?> clazz, final Class<? extends Annotation> annotationClass) {
69          final Collection<Field> fields = getFields(clazz);
70          final Iterator<Field> iterator = fields.iterator();
71  
72          while (iterator.hasNext()) {
73              final Field field = iterator.next();
74              if (!field.isAnnotationPresent(annotationClass)) {
75                  iterator.remove();
76              } else if (!field.isAccessible()) {
77                  try {
78                      field.setAccessible(true);
79                  } catch (SecurityException se) {
80                      log.error("Security exception while setting accessible: " + se);
81                  }
82              }
83          }
84  
85          return fields;
86      }
87  
88      /**
89       * Get methods of an class which are annotated with specific annotation and set them accessible
90       * (if necessary).
91       *
92       * @param clazz           class we are scanning for annotated methods.
93       * @param annotationClass annotation we are interested in
94       * @return a collection containing (accessible) Field objects (or an empty collection)
95       */
96      public static Collection<Method> getAnnotatedMethods(final Class<?> clazz, final Class<? extends Annotation> annotationClass) {
97          final Collection<Method> methods = getMethods(clazz);
98          final Iterator<Method> iterator = methods.iterator();
99  
100         while (iterator.hasNext()) {
101             final Method method = iterator.next();
102             if (!method.isAnnotationPresent(annotationClass)) {
103                 iterator.remove();
104             } else if (!method.isAccessible()) {
105                 try {
106                     method.setAccessible(true);
107                 } catch (SecurityException se) {
108                     log.error("Security exception while setting accessible: " + se);
109                 }
110             }
111         }
112 
113         return methods;
114     }
115 
116     /**
117      * Get the declared fields of a class, including all fields of it's super classes.
118      *
119      * @param clazz class to scan for fields
120      * @return collection of declared Field objects
121      */
122     public static Collection<Field> getFields(Class<?> clazz) {
123         final Map<String, Field> fields = new HashMap<String, Field>();
124 
125         for (; clazz != null;) {
126             for (Field field : clazz.getDeclaredFields()) {
127                 if (!fields.containsKey(field.getName())) {
128                     fields.put(field.getName(), field);
129                 }
130             }
131             clazz = clazz.getSuperclass();
132         }
133 
134         return fields.values();
135     }
136 
137 
138     /**
139      * Get the declared methods of a class, including all methods of it's super classes.
140      *
141      * @param clazz class to scan for methods
142      * @return collection of declared Method objects
143      */
144     public static Collection<Method> getMethods(Class<?> clazz) {
145         final Map<String, Method> methods = new HashMap<String, Method>();
146 
147         for (; clazz != null;) {
148             for (Method method : clazz.getDeclaredMethods()) {
149                 boolean isOverridden = false;
150                 for (Method overriddenMethod : methods.values()) {
151                     if (overriddenMethod.getName().equals(method.getName()) && Arrays.deepEquals(method.getParameterTypes(), overriddenMethod.getParameterTypes())) {
152                         isOverridden = true;
153                         break;
154                     }
155                 }
156                 if (!isOverridden) {
157                     methods.put(method.getName(), method);
158                 }
159             }
160             clazz = clazz.getSuperclass();
161         }
162 
163         return methods.values();
164     }
165 }
166