1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jadira.bindings.core.provider;
17
18 import java.lang.annotation.Annotation;
19 import java.lang.reflect.Constructor;
20 import java.lang.reflect.Method;
21 import java.lang.reflect.Modifier;
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26
27 import org.jadira.bindings.core.annotation.BindingScope;
28 import org.jadira.bindings.core.annotation.DefaultBinding;
29 import org.jadira.bindings.core.binder.ConverterKey;
30 import org.jadira.bindings.core.spi.ConverterProvider;
31 import org.jadira.bindings.core.utils.reflection.TypeHelper;
32
33
34
35
36
37
38 public class AbstractAnnotationMatchingConverterProvider<T extends Annotation, F extends Annotation> implements ConverterProvider {
39
40 public <I,O> Map<ConverterKey<?, ?>, Method> matchToMethods(Class<?> cls) {
41
42 Map<ConverterKey<?, ?>, Method> matchedMethods = new HashMap<ConverterKey<?, ?>, Method>();
43
44 @SuppressWarnings("unchecked")
45 Class<T> toAnnotation = (Class<T>) TypeHelper.getTypeArguments(
46 AbstractAnnotationMatchingConverterProvider.class,
47 this.getClass()).get(0);
48
49 Class<?> loopCls = cls;
50
51 while (loopCls != Object.class) {
52 Method[] methods = loopCls.getDeclaredMethods();
53 for (Method method : methods) {
54 if (signatureIndicatesToMethodCandidate(method)) {
55 T toMethodAnnotation = method.getAnnotation(toAnnotation);
56 if (toMethodAnnotation != null) {
57 List<Class<? extends Annotation>> qualifiers = determineQualifiers(toMethodAnnotation, method.getAnnotations());
58
59 for (Class<? extends Annotation> nextQualifier : qualifiers) {
60 @SuppressWarnings("unchecked")
61 Class<O> returnType = (Class<O>)method.getReturnType();
62
63
64 if (Modifier.isStatic(method.getModifiers())) {
65 @SuppressWarnings("unchecked")
66 Class<I> inputClass = (Class<I>) method.getParameterTypes()[0];
67 matchedMethods.put(new ConverterKey<I,O>(inputClass, returnType, nextQualifier), method);
68 } else {
69 @SuppressWarnings("unchecked")
70 Class<I> inputClass = (Class<I>) cls;
71 matchedMethods.put(new ConverterKey<I,O>(inputClass, returnType, nextQualifier), method);
72 }
73
74 }
75 }
76 }
77 }
78 loopCls = loopCls.getSuperclass();
79 }
80 return matchedMethods;
81 }
82
83 private boolean signatureIndicatesToMethodCandidate(Method method) {
84
85 if (!Modifier.isPublic(method.getModifiers())) {
86 return false;
87 }
88 if (method.getReturnType().equals(Void.TYPE)) {
89 return false;
90 }
91 if (!isToMatch(method)) {
92 return false;
93 }
94 if ((!(Modifier.isStatic(method.getModifiers()) && method.getParameterTypes().length == 1))
95 &&
96 (!(!Modifier.isStatic(method.getModifiers()) && method.getParameterTypes().length == 0))) {
97 return false;
98 }
99 return true;
100 }
101
102 public <I,O> Map<ConverterKey<?,?>, Constructor<O>> matchFromConstructors(Class<O> cls) {
103
104 Map<ConverterKey<?, ?>, Constructor<O>> matchedConstructors = new HashMap<ConverterKey<?, ?>, Constructor<O>>();
105
106 @SuppressWarnings("unchecked")
107 Class<F> fromAnnotation = (Class<F>) TypeHelper.getTypeArguments(
108 AbstractAnnotationMatchingConverterProvider.class,
109 this.getClass()).get(1);
110
111 Class<?> loopCls = cls;
112
113 while (loopCls != Object.class) {
114
115 @SuppressWarnings("unchecked")
116 Constructor<O>[] constructors = (Constructor<O>[])loopCls.getDeclaredConstructors();
117
118 for (Constructor<O> constructor : constructors) {
119 if (signatureIndicatesFromConstructorCandidate(constructor)) {
120 F fromConstructorAnnotation = constructor.getAnnotation(fromAnnotation);
121 if (fromConstructorAnnotation != null) {
122 List<Class<? extends Annotation>> qualifiers = determineQualifiers(fromConstructorAnnotation, constructor.getAnnotations());
123
124 for (Class<? extends Annotation> nextQualifier : qualifiers) {
125 @SuppressWarnings("unchecked")
126 Class<I> paramType = (Class<I>)constructor.getParameterTypes()[0];
127 matchedConstructors.put(new ConverterKey<I,O>((Class<I>)paramType, cls, nextQualifier), constructor);
128 }
129 }
130 }
131 }
132 loopCls = loopCls.getSuperclass();
133 }
134 return matchedConstructors;
135 }
136
137 private boolean signatureIndicatesFromConstructorCandidate(Constructor<?> constructor) {
138
139 if (!Modifier.isPublic(constructor.getModifiers())) {
140 return false;
141 }
142 if (!(constructor.getParameterTypes().length == 1)) {
143 return false;
144 }
145 if (!isFromMatch(constructor)) {
146 return false;
147 }
148 return true;
149 }
150
151 public <I,O> Map<ConverterKey<?,?>, Method> matchFromMethods(Class<?> cls) {
152
153 Map<ConverterKey<?, ?>, Method> matchedMethods = new HashMap<ConverterKey<?, ?>, Method>();
154
155 @SuppressWarnings("unchecked")
156 Class<F> fromAnnotation = (Class<F>) TypeHelper.getTypeArguments(
157 AbstractAnnotationMatchingConverterProvider.class,
158 this.getClass()).get(1);
159
160 Class<?> loopCls = cls;
161
162 while (loopCls != Object.class) {
163 Method[] methods = loopCls.getDeclaredMethods();
164 for (Method method : methods) {
165 if (signatureIndicatesFromMethodCandidate(method)) {
166
167 F fromMethodAnnotation = method.getAnnotation(fromAnnotation);
168 if (fromMethodAnnotation != null) {
169 List<Class<? extends Annotation>> qualifiers = determineQualifiers(fromMethodAnnotation, method.getAnnotations());
170
171 for (Class<? extends Annotation> nextQualifier : qualifiers) {
172 @SuppressWarnings("unchecked")
173 Class<I> paramType = (Class<I>)method.getParameterTypes()[0];
174 @SuppressWarnings("unchecked")
175 Class<O> outputClass = (Class<O>)cls;
176 matchedMethods.put(new ConverterKey<I,O>(paramType, outputClass, nextQualifier), method);
177 }
178 }
179 }
180 }
181 loopCls = loopCls.getSuperclass();
182 }
183 return matchedMethods;
184 }
185
186 private boolean signatureIndicatesFromMethodCandidate(Method method) {
187
188 if (!Modifier.isPublic(method.getModifiers())) {
189 return false;
190 }
191 if (method.getReturnType().equals(Void.TYPE)) {
192 return false;
193 }
194 if (!(Modifier.isStatic(method.getModifiers()) && method.getParameterTypes().length == 1)) {
195 return false;
196 }
197 if (!isFromMatch(method)) {
198 return false;
199 }
200 return true;
201 }
202
203
204
205
206
207
208 protected boolean isToMatch(Method method) {
209 return true;
210 }
211
212
213
214
215
216
217 protected boolean isFromMatch(Constructor<?> constructor) {
218 return true;
219 }
220
221
222
223
224
225
226 protected boolean isFromMatch(Method method) {
227 return true;
228 }
229
230
231
232
233
234
235
236
237
238 protected List<Class<? extends Annotation>> determineQualifiers(Annotation bindingAnnotation, Annotation... allAnnotations) {
239
240 List<Class<? extends Annotation>> result = new ArrayList<Class<? extends Annotation>>();
241
242
243 Class<? extends Annotation> bindingAnnotationType = bindingAnnotation.annotationType();
244 if (bindingAnnotationType.getAnnotation(BindingScope.class) != null) {
245 result.add(bindingAnnotationType);
246 }
247
248
249 for (Annotation next : bindingAnnotation.annotationType().getAnnotations()) {
250 Class<? extends Annotation> nextType = next.annotationType();
251 if (nextType.getAnnotation(BindingScope.class) != null) {
252 result.add(nextType);
253 }
254 }
255
256
257 for (Annotation next : allAnnotations) {
258 Class<? extends Annotation> nextType = next.annotationType();
259 if (nextType.getAnnotation(BindingScope.class) != null) {
260 result.add(nextType);
261 }
262 }
263
264 if (result.isEmpty()) {
265 result.add(DefaultBinding.class);
266 }
267
268 return result;
269 }
270
271 }