1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.seasar.cubby.plugins.s2.spi;
18
19 import static org.seasar.cubby.internal.util.ReflectionUtils.findAllDeclaredField;
20
21 import java.lang.annotation.Annotation;
22 import java.lang.reflect.Field;
23 import java.lang.reflect.Method;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.LinkedHashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31
32 import org.seasar.cubby.spi.BeanDescProvider;
33 import org.seasar.cubby.spi.beans.Attribute;
34 import org.seasar.cubby.spi.beans.BeanDesc;
35 import org.seasar.cubby.spi.beans.IllegalAttributeException;
36 import org.seasar.cubby.spi.beans.ParameterizedClassDesc;
37 import org.seasar.cubby.spi.beans.impl.DefaultBeanDescProvider;
38 import org.seasar.framework.beans.IllegalPropertyRuntimeException;
39 import org.seasar.framework.beans.PropertyDesc;
40 import org.seasar.framework.util.Disposable;
41 import org.seasar.framework.util.DisposableUtil;
42
43
44
45
46
47
48
49
50
51
52
53
54
55 public class S2BeanDescProvider extends DefaultBeanDescProvider {
56
57 private static volatile boolean initialized;
58
59 private void initialize() {
60 if (!initialized) {
61 DisposableUtil.add(new Disposable() {
62
63 public void dispose() {
64 beanDescCache.clear();
65 initialized = false;
66 }
67
68 });
69 initialized = true;
70 }
71 }
72
73
74
75
76 @Override
77 public BeanDesc getBeanDesc(final Class<?> clazz) {
78 initialize();
79 return super.getBeanDesc(clazz);
80 }
81
82
83
84
85 @Override
86 protected BeanDesc createBeanDesc(final Class<?> clazz) {
87 return new S2BeanDescImpl(clazz);
88 }
89
90
91
92
93
94
95
96
97
98 private static class S2BeanDescImpl extends BeanDescImpl {
99
100
101 private Set<Field> recognizedAsPropertyFields;
102
103
104
105
106
107
108
109 S2BeanDescImpl(final Class<?> clazz) {
110 super(clazz);
111 }
112
113
114
115
116 @Override
117 protected Map<String, Attribute> collectPropertyAttributeMap(
118 final Class<?> clazz) {
119 this.recognizedAsPropertyFields = new HashSet<Field>();
120 final org.seasar.framework.beans.BeanDesc s2BeanDesc = org.seasar.framework.beans.factory.BeanDescFactory
121 .getBeanDesc(clazz);
122 final Map<String, Attribute> attributes = new LinkedHashMap<String, Attribute>();
123 for (int i = 0; i < s2BeanDesc.getPropertyDescSize(); i++) {
124 final org.seasar.framework.beans.PropertyDesc propertyDesc = s2BeanDesc
125 .getPropertyDesc(i);
126 final Attribute attribute = new S2PropertyAttribute(
127 propertyDesc);
128 if (!propertyDesc.hasReadMethod()
129 && !propertyDesc.hasWriteMethod()) {
130 final Field field = propertyDesc.getField();
131 if (field != null) {
132 recognizedAsPropertyFields.add(field);
133 }
134 }
135 attributes.put(propertyDesc.getPropertyName(), attribute);
136 }
137 return attributes;
138 }
139
140
141
142
143 @Override
144 protected Map<String, List<Attribute>> collectFieldAttributesMap(
145 final Class<?> clazz) {
146 final Map<String, List<Attribute>> fieldAttributes = new LinkedHashMap<String, List<Attribute>>();
147 for (final Field field : findAllDeclaredField(clazz)) {
148 if (recognizedAsPropertyFields.contains(field)) {
149 continue;
150 }
151 final String fieldName = field.getName();
152 List<Attribute> fieldDescs;
153 if (!fieldAttributes.containsKey(fieldName)) {
154 fieldDescs = new ArrayList<Attribute>();
155 fieldAttributes.put(fieldName, fieldDescs);
156 } else {
157 fieldDescs = fieldAttributes.get(fieldName);
158 }
159 final Attribute attributes = new FieldAttribute(clazz, field);
160 fieldDescs.add(attributes);
161 }
162 return fieldAttributes;
163 }
164
165 }
166
167
168
169
170
171
172
173
174
175 private static class S2PropertyAttribute implements Attribute {
176
177
178 private final org.seasar.framework.beans.PropertyDesc s2PropertyDesc;
179
180
181 private final ParameterizedClassDesc parameterizedClassDesc;
182
183
184 private final Map<Class<? extends Annotation>, Annotation> annotationCache = new HashMap<Class<? extends Annotation>, Annotation>();
185
186
187
188
189
190
191
192 S2PropertyAttribute(
193 final org.seasar.framework.beans.PropertyDesc s2PropertyDesc) {
194 this.s2PropertyDesc = s2PropertyDesc;
195 this.parameterizedClassDesc = new S2ParameterizedClassDesc(
196 s2PropertyDesc.getParameterizedClassDesc());
197 }
198
199
200
201
202 public String getName() {
203 return s2PropertyDesc.getPropertyName();
204 }
205
206
207
208
209 public Class<?> getType() {
210 return s2PropertyDesc.getPropertyType();
211 }
212
213
214
215
216 public boolean isReadable() {
217 return s2PropertyDesc.isReadable();
218 }
219
220
221
222
223 public boolean isWritable() {
224 return s2PropertyDesc.isWritable();
225 }
226
227
228
229
230 public Object getValue(final Object target)
231 throws IllegalAttributeException {
232 try {
233 return s2PropertyDesc.getValue(target);
234 } catch (final IllegalPropertyRuntimeException e) {
235 throw new IllegalAttributeException(e.getTargetClass(), e
236 .getPropertyName(), e);
237 }
238 }
239
240
241
242
243 public void setValue(final Object target, final Object value)
244 throws IllegalAttributeException {
245 try {
246 s2PropertyDesc.setValue(target, value);
247 } catch (final IllegalPropertyRuntimeException e) {
248 throw new IllegalAttributeException(e.getTargetClass(), e
249 .getPropertyName(), e);
250 }
251 }
252
253
254
255
256 public ParameterizedClassDesc getParameterizedClassDesc() {
257 return parameterizedClassDesc;
258 }
259
260
261
262
263 public <T extends Annotation> T getAnnotation(
264 final Class<T> annotationClass) {
265 if (annotationCache.containsKey(annotationClass)) {
266 return annotationClass.cast(annotationCache
267 .get(annotationClass));
268 }
269
270 if (s2PropertyDesc.hasReadMethod()) {
271 final Method method = s2PropertyDesc.getReadMethod();
272 final T annotation = findAnnotation(annotationClass, method);
273 if (annotation != null) {
274 annotationCache.put(annotationClass, annotation);
275 return annotation;
276 }
277 }
278 if (s2PropertyDesc.hasWriteMethod()) {
279 final Method method = s2PropertyDesc.getWriteMethod();
280 final T annotation = findAnnotation(annotationClass, method);
281 if (annotation != null) {
282 annotationCache.put(annotationClass, annotation);
283 return annotation;
284 }
285 }
286 final Field field = s2PropertyDesc.getField();
287 if (field != null) {
288 final T annotation = field.getAnnotation(annotationClass);
289 if (annotation != null) {
290 annotationCache.put(annotationClass, annotation);
291 return field.getAnnotation(annotationClass);
292 }
293 }
294 return null;
295 }
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312 private static <T extends Annotation> T findAnnotation(
313 final Class<T> annotationClass, final Method method) {
314 final String methodName = method.getName();
315 final Class<?>[] parameterTypes = method.getParameterTypes();
316 for (Class<?> target = method.getDeclaringClass(); !target
317 .equals(Object.class); target = target.getSuperclass()) {
318 final T annotation = getAnnotation(annotationClass, target,
319 methodName, parameterTypes);
320 if (annotation != null) {
321 return annotation;
322 }
323 final T annotationOfInterfaces = getAnnotationOfInterfaces(
324 annotationClass, target, methodName, parameterTypes);
325 if (annotationOfInterfaces != null) {
326 return annotationOfInterfaces;
327 }
328 }
329 return null;
330 }
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348 private static <T extends Annotation> T getAnnotationOfInterfaces(
349 final Class<T> annotationClass, final Class<?> clazz,
350 final String methodName, final Class<?>[] parameterTypes) {
351 for (final Class<?> interfaceClass : clazz.getInterfaces()) {
352 final T annotation = getAnnotation(annotationClass,
353 interfaceClass, methodName, parameterTypes);
354 if (annotation != null) {
355 return annotation;
356 }
357 }
358 return null;
359 }
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377 private static <T extends Annotation> T getAnnotation(
378 final Class<T> annotationClass, final Class<?> clazz,
379 final String methodName,
380 @SuppressWarnings("unchecked") final Class[] parameterTypes) {
381 try {
382 final Method method = clazz.getDeclaredMethod(methodName,
383 parameterTypes);
384 if (method.isAnnotationPresent(annotationClass)) {
385 return method.getAnnotation(annotationClass);
386 }
387 } catch (final NoSuchMethodException e) {
388
389 }
390
391 return null;
392 }
393
394
395
396
397 public boolean isAnnotationPresent(
398 final Class<? extends Annotation> annotationClass) {
399 return this.getAnnotation(annotationClass) != null;
400 }
401
402
403
404
405 @Override
406 public int hashCode() {
407 final int prime = 31;
408 int result = 1;
409 result = prime
410 * result
411 + ((s2PropertyDesc == null) ? 0 : s2PropertyDesc.hashCode());
412 result = prime * result
413 + s2PropertyDesc.getBeanDesc().getBeanClass().hashCode();
414 result = prime * result
415 + s2PropertyDesc.getPropertyName().hashCode();
416 return result;
417 }
418
419
420
421
422 @Override
423 public boolean equals(final Object obj) {
424 if (this == obj) {
425 return true;
426 }
427 if (obj == null) {
428 return false;
429 }
430 if (getClass() != obj.getClass()) {
431 return false;
432 }
433
434 if (this == obj) {
435 return true;
436 }
437 if (obj == null) {
438 return false;
439 }
440 if (getClass() != obj.getClass()) {
441 return false;
442 }
443 final S2PropertyAttribute other = (S2PropertyAttribute) obj;
444 if (s2PropertyDesc == null) {
445 if (other.s2PropertyDesc != null) {
446 return false;
447 }
448 } else {
449 if (!s2PropertyDesc.getBeanDesc().getBeanClass().equals(
450 other.s2PropertyDesc.getBeanDesc().getBeanClass())) {
451 return false;
452 }
453 if (!s2PropertyDesc.getPropertyName().equals(
454 other.s2PropertyDesc.getPropertyName())) {
455 return false;
456 }
457 }
458 return true;
459 }
460
461 }
462
463
464
465
466
467
468
469
470
471
472 private static class S2ParameterizedClassDesc implements
473 ParameterizedClassDesc {
474
475
476 private final org.seasar.framework.beans.ParameterizedClassDesc s2ParameterizedClassDesc;
477
478
479
480
481
482
483
484
485 S2ParameterizedClassDesc(
486 final org.seasar.framework.beans.ParameterizedClassDesc s2ParameterizedClassDesc) {
487 this.s2ParameterizedClassDesc = s2ParameterizedClassDesc;
488 }
489
490
491
492
493 public boolean isParameterizedClass() {
494 return s2ParameterizedClassDesc.isParameterizedClass();
495 }
496
497
498
499
500 public Class<?> getRawClass() {
501 return s2ParameterizedClassDesc.getRawClass();
502 }
503
504
505
506
507 public ParameterizedClassDesc[] getArguments() {
508 final org.seasar.framework.beans.ParameterizedClassDesc[] s2Arguments = this.s2ParameterizedClassDesc
509 .getArguments();
510 final List<ParameterizedClassDesc> arguments = new ArrayList<ParameterizedClassDesc>(
511 s2Arguments.length);
512 for (final org.seasar.framework.beans.ParameterizedClassDesc s2Argument : s2Arguments) {
513 final S2ParameterizedClassDesc argument = new S2ParameterizedClassDesc(
514 s2Argument);
515 arguments.add(argument);
516 }
517 return arguments.toArray(new ParameterizedClassDesc[0]);
518 }
519
520 }
521
522 }