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