1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.callbackparams.internal.template.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.util.ArrayList;
25 import java.util.Collections;
26 import java.util.List;
27 import org.callbackparams.ext.WrappingCallbackImpls;
28 import org.callbackparams.wrap.legacy.Wrapping;
29
30
31
32
33 enum WrappingClassLocator {
34
35 IMPL_ON_ENUM_CONSTANT {
36 @Override List<Class<? extends Wrapping>[]> locateClasses(Object value) {
37 return asWrappingClassList(asEnumConstantField(value)
38 .getAnnotation(WrappingCallbackImpls.class));
39 }
40 },
41
42 @CanBeSubclassedByClassSpecifiedImpl
43 IMPL_ON_ENUM_CONSTANT_ANNOTATION {
44 @Override List<Class<? extends Wrapping>[]> locateClasses(Object value) {
45 List<Class<? extends Wrapping>[]> wrappingList =
46 new ArrayList<Class<? extends Wrapping>[]>();
47 for (Annotation a : asEnumConstantField(value).getAnnotations()) {
48 final WrappingCallbackImpls implsOnAnnotation = a
49 .annotationType()
50 .getAnnotation(WrappingCallbackImpls.class);
51 if (null != implsOnAnnotation) {
52 wrappingList.add(implsOnAnnotation.value());
53 }
54 }
55 return wrappingList;
56 }
57 },
58
59 IMPL_ON_ENUM_CLASS_OR_VALUE_CLASS {
60
61 private WrappingCallbackImpls findImplOn(Class<?> c) {
62 for (Annotation a : c.getDeclaredAnnotations()) {
63 if (WrappingCallbackImpls.class == a.annotationType()) {
64 return (WrappingCallbackImpls) a;
65 }
66 }
67 return null;
68 }
69
70 @Override List<Class<? extends Wrapping>[]> locateClasses(Object value) {
71 WrappingCallbackImpls wrappingImpl = findImplOn(value.getClass());
72 if (null == wrappingImpl) {
73 AnnotatedElement possibleEnumField = asEnumConstantField(value);
74 if (possibleEnumField instanceof Field) {
75 wrappingImpl = findImplOn(
76 ((Field)possibleEnumField).getDeclaringClass());
77 }
78 }
79 return asWrappingClassList(wrappingImpl);
80 }
81 },
82
83 @CanBeSubclassedByClassSpecifiedImpl
84 IMPL_ON_CLASS_ANNOTATION_OR_IMPL_ON_SUPER_CLASS {
85
86 @Override List<Class<? extends Wrapping>[]> locateClasses(Object value) {
87 Class<?> c = value.getClass();
88 final WrappingCallbackImpls superClassImpl =
89 c.getAnnotation(WrappingCallbackImpls.class);
90 final List<Class<? extends Wrapping>[]> wrappingList =
91 new ArrayList<Class<? extends Wrapping>[]>();
92
93 LOOP_THROUGH_CLASS_HIERARCY: do {
94 for (Annotation a : c.getDeclaredAnnotations()) {
95 if (a == superClassImpl) {
96 break LOOP_THROUGH_CLASS_HIERARCY;
97 } else {
98 WrappingCallbackImpls annotationImpl = a.annotationType()
99 .getAnnotation(WrappingCallbackImpls.class);
100 if (null != annotationImpl) {
101 wrappingList.add(annotationImpl.value());
102 }
103 }
104 }
105 if (false == wrappingList.isEmpty()) {
106 return wrappingList;
107 }
108 } while (Object.class != (c = c.getSuperclass()));
109 return asWrappingClassList(superClassImpl);
110 }
111 };
112
113 private static final AnnotatedElement NOT_AN_ENUM_CONSTANT =
114 new AnnotatedElement() {
115 private final Annotation[] NO_ANNOTATIONS = {};
116
117 public <T extends Annotation> T getAnnotation(
118 Class<T> annotationClass) { return null; }
119 public Annotation[] getAnnotations() { return NO_ANNOTATIONS; }
120 public Annotation[] getDeclaredAnnotations() { return NO_ANNOTATIONS; }
121 public boolean isAnnotationPresent(
122 Class<? extends Annotation> annotationClass) { return false; }
123 };
124
125 private static AnnotatedElement asEnumConstantField(Object value) {
126 if (value instanceof Enum<?>) {
127 final Enum<?> enumConstant = (Enum<?>) value;
128 try {
129 Field enumConstantField = enumConstant.getDeclaringClass()
130 .getField(enumConstant.name());
131 try {
132 enumConstantField.setAccessible(true);
133 } catch (SecurityException ignoreAndTryToContinueAnyway) {}
134 if (enumConstantField.isEnumConstant()
135 && enumConstant == enumConstantField.get(null)) {
136 return enumConstantField;
137 }
138 } catch (Throwable ignore) {
139
140
141
142
143 }
144 }
145 return NOT_AN_ENUM_CONSTANT;
146 }
147
148 private static List<Class<? extends Wrapping>[]> asWrappingClassList(
149 WrappingCallbackImpls possibleImpl) {
150 if (null == possibleImpl) {
151 return Collections.<Class<? extends Wrapping>[]>emptyList();
152 } else {
153 return Collections.singletonList(possibleImpl.value());
154 }
155 }
156
157 boolean canBeSubclassedByClassSpecifiedImpl() {
158 return asEnumConstantField(this)
159 .isAnnotationPresent(CanBeSubclassedByClassSpecifiedImpl.class);
160 }
161
162 abstract List<Class<? extends Wrapping>[]> locateClasses(Object value);
163
164 @Retention(RetentionPolicy.RUNTIME)
165 @interface CanBeSubclassedByClassSpecifiedImpl {}
166 }