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