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