View Javadoc

1   /*
2    * Copyright 2012-2013 the original author or authors.
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.callbackparams.support.annotation;
18  
19  import java.lang.annotation.Annotation;
20  import java.lang.annotation.Retention;
21  import java.lang.annotation.RetentionPolicy;
22  import java.lang.reflect.AnnotatedElement;
23  import java.lang.reflect.Field;
24  import java.lang.reflect.Modifier;
25  import java.util.ArrayList;
26  import java.util.Collection;
27  import java.util.List;
28  import org.callbackparams.support.ExceptionUtil;
29  
30  /**
31   * @author Henrik Kaipe
32   */
33  public class AnnotationInjector
34  extends org.callbackparams.support.AnnotationInjector {
35  
36      @Override
37      protected void injectAnnotationsInternal(Object target, Object enumConstant)
38      {
39          Field enumField = findEnumField(enumConstant);
40          if (null == enumField) {
41              return;
42          }
43          Class<?> enumClass = enumField.getDeclaringClass();
44          Package enumPackage = enumClass.getPackage();
45          AnnotatedElement[] annotatedElements = null == enumPackage
46                  ? new AnnotatedElement[]{enumField, enumClass}
47                  : new AnnotatedElement[]{enumField, enumClass, enumPackage};
48  
49          Collection<Field> injectableFields =
50                  findInjectableField(target.getClass());
51          checkForClassRetention(injectableFields);
52          for (Field f : injectableFields) {
53              Annotation a = findAnnotation(f.getType(), annotatedElements);
54  
55              if (null != a) {
56                  try {
57                      f.setAccessible(true);
58                  } catch (SecurityException ignoreAndContinueAnyway___) {}
59                  try {
60                      f.set(target, a);
61                  } catch (Exception ex) {
62                      throw ExceptionUtil.unchecked(ex);
63                  }
64              }
65          }
66      }
67  
68      private static Annotation findAnnotation(
69              Class<?> annotationClass, AnnotatedElement[] elements) {
70          Class<? extends Annotation> c =
71                  annotationClass.asSubclass(Annotation.class);
72          for (AnnotatedElement ae : elements) {
73              Annotation a = ae.getAnnotation(c);
74              if (null != a) {
75                  return a;
76              }
77          }
78          return null;
79      }
80  
81      private static Field findEnumField(Object enumConstant) {
82          Class<? extends Enum> c = findEnumSuperClass(enumConstant.getClass());
83          if (null == c) {
84              return null;
85          } else {
86              try {
87                  return c.getField(((Enum) enumConstant).name());
88              } catch (Exception ex) {
89                  throw ExceptionUtil.unchecked(ex);
90              }
91          }
92      }
93  
94      private static Class<? extends Enum> findEnumSuperClass(Class<?> c) {
95          if (c.isEnum()) {
96              return c.asSubclass(Enum.class);
97          } else if (Object.class == c) {
98              return null;
99          } else {
100             return findEnumSuperClass(c.getSuperclass());
101         }
102     }
103 
104     private static Collection<Field> findInjectableField(Class<?> targetClass) {
105         if (Object.class == targetClass) {
106             return new ArrayList<Field>();
107         }
108 
109         Collection<Field> injectableFields =
110                 findInjectableField(targetClass.getSuperclass());
111         for (Field f : targetClass.getDeclaredFields()) {
112             if (isNonStaticAndNonFinal(f) && isAnnotationClass(f.getType())) {
113                 injectableFields.add(f);
114             }
115         }
116         return injectableFields;
117     }
118 
119     private static boolean isNonStaticAndNonFinal(Field f) {
120         int modifiers = f.getModifiers();
121         return false == Modifier.isStatic(modifiers)
122                 && false == Modifier.isFinal(modifiers);
123     }
124 
125     private static boolean isAnnotationClass(Class<?> c) {
126         Retention retention = c.getAnnotation(Retention.class);
127         return null == retention
128                 ? c.isAnnotation()
129                 : RetentionPolicy.RUNTIME == retention.value();
130     }
131 
132     private static void checkForClassRetention(Collection<Field> injectableFields) {
133         List<Field> fieldsWithClassRetention = new ArrayList<Field>();
134         for (Field f : injectableFields) {
135             if (false == f.getType().isAnnotationPresent(Retention.class)) {
136                 fieldsWithClassRetention.add(f);
137             }
138         }
139         if (false == fieldsWithClassRetention.isEmpty()) {
140             throw new Error("Annotation classes that are not annotated with "
141                     + "@Retention(RetentionPolicy.RUNTIME) cannot be injected: "
142                     + fieldsWithClassRetention);
143         }
144     }
145 }