View Javadoc

1   /*
2    * Copyright 2004-2010 the Seasar Foundation and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  
17  package org.seasar.cubby.spi.beans.impl;
18  
19  import static org.seasar.cubby.internal.util.ReflectionUtils.findAllDeclaredField;
20  
21  import java.beans.BeanInfo;
22  import java.beans.IntrospectionException;
23  import java.beans.Introspector;
24  import java.beans.PropertyDescriptor;
25  import java.lang.annotation.Annotation;
26  import java.lang.annotation.Inherited;
27  import java.lang.reflect.Array;
28  import java.lang.reflect.Field;
29  import java.lang.reflect.GenericArrayType;
30  import java.lang.reflect.InvocationTargetException;
31  import java.lang.reflect.Method;
32  import java.lang.reflect.Modifier;
33  import java.lang.reflect.ParameterizedType;
34  import java.lang.reflect.Proxy;
35  import java.lang.reflect.Type;
36  import java.util.ArrayList;
37  import java.util.Collections;
38  import java.util.HashMap;
39  import java.util.LinkedHashMap;
40  import java.util.LinkedHashSet;
41  import java.util.List;
42  import java.util.Map;
43  import java.util.Set;
44  import java.util.concurrent.ConcurrentHashMap;
45  
46  import org.seasar.cubby.spi.BeanDescProvider;
47  import org.seasar.cubby.spi.beans.Attribute;
48  import org.seasar.cubby.spi.beans.AttributeNotFoundException;
49  import org.seasar.cubby.spi.beans.BeanDesc;
50  import org.seasar.cubby.spi.beans.IllegalAttributeException;
51  import org.seasar.cubby.spi.beans.ParameterizedClassDesc;
52  
53  /**
54   * {@link BeanDesc} のプロバイダの標準的な実装です。
55   * <p>
56   * {@link Introspector} によって生成されるメタ情報とそのフィールドの情報を元に {@link BeanDesc} を構築します。
57   * </p>
58   * 
59   * @author baba
60   */
61  public class DefaultBeanDescProvider implements BeanDescProvider {
62  
63  	/** プリミティブ型のデフォルト値の <code>Map</code>。 */
64  	private static final Map<Class<?>, Object> PRIMITIVE_TYPE_DEFAULT_VALUES;
65  	static {
66  		final Map<Class<?>, Object> map = new HashMap<Class<?>, Object>();
67  		map.put(boolean.class, Boolean.FALSE);
68  		map.put(char.class, Character.valueOf('\u0000'));
69  		map.put(byte.class, Byte.valueOf((byte) 0));
70  		map.put(short.class, Short.valueOf((short) 0));
71  		map.put(int.class, Integer.valueOf(0));
72  		map.put(long.class, Long.valueOf(0L));
73  		map.put(float.class, Float.valueOf(0F));
74  		map.put(double.class, Double.valueOf(0D));
75  		PRIMITIVE_TYPE_DEFAULT_VALUES = Collections.unmodifiableMap(map);
76  	}
77  
78  	/** <code>BeanDesc</code> のキャッシュ。 */
79  	protected final Map<Class<?>, BeanDesc> beanDescCache = new ConcurrentHashMap<Class<?>, BeanDesc>(
80  			1024);
81  
82  	/**
83  	 * {@inheritDoc}
84  	 */
85  	public BeanDesc getBeanDesc(final Class<?> clazz) {
86  		if (beanDescCache.containsKey(clazz)) {
87  			return beanDescCache.get(clazz);
88  		}
89  
90  		synchronized (clazz) {
91  			if (beanDescCache.containsKey(clazz)) {
92  				return beanDescCache.get(clazz);
93  			}
94  
95  			final BeanDesc beanDesc = createBeanDesc(clazz);
96  			beanDescCache.put(clazz, beanDesc);
97  			return beanDesc;
98  		}
99  	}
100 
101 	/**
102 	 * {@link BeanDesc} を生成します。
103 	 * 
104 	 * @param clazz
105 	 *            操作対象のクラス
106 	 * @return {@link BeanDesc}
107 	 */
108 	protected BeanDesc createBeanDesc(final Class<?> clazz) {
109 		return new BeanDescImpl(clazz);
110 	}
111 
112 	/**
113 	 * {@link BeanDesc} の実装です。
114 	 * 
115 	 * @author baba
116 	 */
117 	protected static class BeanDescImpl implements BeanDesc {
118 
119 		/** 操作対象のクラス。 */
120 		private final Class<?> clazz;
121 
122 		/** プロパティの属性。 */
123 		private final Map<String, Attribute> propertyAttributeMap;
124 
125 		/** フィールドの属性。 */
126 		private final Map<String, List<Attribute>> fieldAttributesMap;
127 
128 		/**
129 		 * インスタンス化します。
130 		 * 
131 		 * @param clazz
132 		 *            操作対象のクラス
133 		 */
134 		public BeanDescImpl(final Class<?> clazz) {
135 			this.clazz = clazz;
136 			this.propertyAttributeMap = collectPropertyAttributeMap(clazz);
137 			this.fieldAttributesMap = collectFieldAttributesMap(clazz);
138 		}
139 
140 		/**
141 		 * 指定されたクラスからプロパティの {@link Attribute} を生成します。
142 		 * 
143 		 * @param clazz
144 		 *            対象のクラス
145 		 * @return {@link Attribute} の {@link Map}
146 		 */
147 		protected Map<String, Attribute> collectPropertyAttributeMap(
148 				final Class<?> clazz) {
149 			final Map<String, Attribute> propertyAttributes = new LinkedHashMap<String, Attribute>();
150 			final BeanInfo beanInfo;
151 			try {
152 				beanInfo = Introspector.getBeanInfo(clazz);
153 			} catch (final IntrospectionException e) {
154 				throw new IllegalStateException(e);
155 			}
156 			for (final PropertyDescriptor propertyDescriptor : beanInfo
157 					.getPropertyDescriptors()) {
158 				final String propertyName = propertyDescriptor.getName();
159 				final Attribute propertyDesc = new PropertyAttribute(clazz,
160 						propertyDescriptor);
161 				propertyAttributes.put(propertyName, propertyDesc);
162 			}
163 			return propertyAttributes;
164 		}
165 
166 		/**
167 		 * 指定されたクラスからフィールドの {@link Attribute} を生成します。
168 		 * 
169 		 * @param clazz
170 		 *            対象のクラス
171 		 * @return {@link Attribute} の {@link Map}
172 		 */
173 		protected Map<String, List<Attribute>> collectFieldAttributesMap(
174 				final Class<?> clazz) {
175 			final Map<String, List<Attribute>> fieldAttributes = new LinkedHashMap<String, List<Attribute>>();
176 			for (final Field field : findAllDeclaredField(clazz)) {
177 				final String fieldName = field.getName();
178 				List<Attribute> fieldDescs;
179 				if (!fieldAttributes.containsKey(fieldName)) {
180 					fieldDescs = new ArrayList<Attribute>();
181 					fieldAttributes.put(fieldName, fieldDescs);
182 				} else {
183 					fieldDescs = fieldAttributes.get(fieldName);
184 				}
185 				final Attribute attributes = new FieldAttribute(clazz, field);
186 				fieldDescs.add(attributes);
187 			}
188 			return fieldAttributes;
189 		}
190 
191 		/**
192 		 * {@inheritDoc}
193 		 */
194 		public boolean hasPropertyAttribute(final String name) {
195 			return propertyAttributeMap.containsKey(name);
196 		}
197 
198 		/**
199 		 * {@inheritDoc}
200 		 */
201 		public Attribute getPropertyAttribute(final String name)
202 				throws AttributeNotFoundException {
203 			if (!propertyAttributeMap.containsKey(name)) {
204 				throw new AttributeNotFoundException(clazz, name);
205 			}
206 			return propertyAttributeMap.get(name);
207 		}
208 
209 		/**
210 		 * {@inheritDoc}
211 		 */
212 		public Set<Attribute> findtPropertyAttributes() {
213 			final Set<Attribute> attributes = new LinkedHashSet<Attribute>();
214 			attributes.addAll(propertyAttributeMap.values());
215 			return Collections.unmodifiableSet(attributes);
216 		}
217 
218 		/**
219 		 * {@inheritDoc}
220 		 */
221 		public Attribute getFieldAttribute(final String fieldName) {
222 			if (!fieldAttributesMap.containsKey(fieldName)) {
223 				throw new AttributeNotFoundException(clazz, fieldName);
224 			}
225 			return fieldAttributesMap.get(fieldName).get(0);
226 		}
227 
228 		/**
229 		 * {@inheritDoc}
230 		 */
231 		public boolean hasFieldAttribute(final String fieldName) {
232 			return fieldAttributesMap.containsKey(fieldName);
233 		}
234 
235 		/**
236 		 * {@inheritDoc}
237 		 */
238 		public Set<Attribute> findFieldAttributes() {
239 			final Set<Attribute> fieldAttributes = new LinkedHashSet<Attribute>();
240 			for (final List<Attribute> attributes : fieldAttributesMap.values()) {
241 				fieldAttributes.addAll(attributes);
242 			}
243 			return Collections.unmodifiableSet(fieldAttributes);
244 		}
245 
246 		/**
247 		 * {@inheritDoc}
248 		 */
249 		public Set<Attribute> findAllAttributes() {
250 			final Set<Attribute> attributes = new LinkedHashSet<Attribute>();
251 			attributes.addAll(this.findtPropertyAttributes());
252 			attributes.addAll(this.findFieldAttributes());
253 			return Collections.unmodifiableSet(attributes);
254 		}
255 
256 		/**
257 		 * {@inheritDoc}
258 		 */
259 		public Set<Attribute> findAttributesAnnotatedWith(
260 				final Class<? extends Annotation> annotationClass) {
261 			final Set<Attribute> attributes = new LinkedHashSet<Attribute>();
262 			for (final Attribute attribute : findAllAttributes()) {
263 				if (attribute.isAnnotationPresent(annotationClass)) {
264 					attributes.add(attribute);
265 				}
266 			}
267 			return Collections.unmodifiableSet(attributes);
268 		}
269 
270 	}
271 
272 	/**
273 	 * プロパティに対する {@link Attribute} の実装です。
274 	 * 
275 	 * @author baba
276 	 */
277 	protected static class PropertyAttribute implements Attribute {
278 
279 		/** 操作対象のクラス。 */
280 		private final Class<?> clazz;
281 
282 		/** プロパティの記述。 */
283 		private final PropertyDescriptor propertyDescriptor;
284 
285 		/** パラメタ化されたクラスの記述。 */
286 		private final ParameterizedClassDesc parameterizedClassDesc;
287 
288 		/** アノテーションのキャッシュ。 */
289 		private final Map<Class<? extends Annotation>, Annotation> annotationCache = new HashMap<Class<? extends Annotation>, Annotation>();
290 
291 		/**
292 		 * インスタンス化します。
293 		 * 
294 		 * @param clazz
295 		 *            操作対象のクラス
296 		 * @param propertyDescriptor
297 		 *            プロパティの記述
298 		 */
299 		PropertyAttribute(final Class<?> clazz,
300 				final PropertyDescriptor propertyDescriptor) {
301 			this.clazz = clazz;
302 			this.propertyDescriptor = propertyDescriptor;
303 
304 			if (propertyDescriptor.getReadMethod() != null) {
305 				this.parameterizedClassDesc = createParameterizedClassDesc(propertyDescriptor
306 						.getReadMethod().getGenericReturnType());
307 			} else if (propertyDescriptor.getWriteMethod() != null) {
308 				this.parameterizedClassDesc = createParameterizedClassDesc(propertyDescriptor
309 						.getWriteMethod().getParameterTypes()[0]);
310 			} else {
311 				this.parameterizedClassDesc = null;
312 			}
313 		}
314 
315 		/**
316 		 * {@inheritDoc}
317 		 */
318 		public String getName() {
319 			return propertyDescriptor.getName();
320 		}
321 
322 		/**
323 		 * {@inheritDoc}
324 		 */
325 		public Class<?> getType() {
326 			return propertyDescriptor.getPropertyType();
327 		}
328 
329 		/**
330 		 * {@inheritDoc}
331 		 */
332 		public boolean isReadable() {
333 			return propertyDescriptor.getReadMethod() != null;
334 		}
335 
336 		/**
337 		 * {@inheritDoc}
338 		 */
339 		public boolean isWritable() {
340 			return propertyDescriptor.getWriteMethod() != null;
341 		}
342 
343 		/**
344 		 * {@inheritDoc}
345 		 */
346 		public Object getValue(final Object target)
347 				throws IllegalAttributeException {
348 			final Method method = propertyDescriptor.getReadMethod();
349 			if (method == null) {
350 				throw new IllegalAttributeException(clazz, propertyDescriptor
351 						.getName(), new IllegalStateException(
352 						propertyDescriptor.getName() + " is not readable."));
353 			}
354 			try {
355 				return method.invoke(target);
356 			} catch (final IllegalAccessException e) {
357 				throw new IllegalAttributeException(clazz, propertyDescriptor
358 						.getName(), e);
359 			} catch (final InvocationTargetException e) {
360 				final Throwable t = e.getTargetException();
361 				if (t instanceof Error) {
362 					throw (Error) t;
363 				}
364 				throw new IllegalAttributeException(clazz, propertyDescriptor
365 						.getName(), e);
366 			}
367 		}
368 
369 		/**
370 		 * {@inheritDoc}
371 		 */
372 		public void setValue(final Object target, final Object value)
373 				throws IllegalAttributeException {
374 			final Method method = propertyDescriptor.getWriteMethod();
375 			if (method == null) {
376 				throw new IllegalAttributeException(clazz, propertyDescriptor
377 						.getName(), new IllegalStateException(
378 						propertyDescriptor.getName() + " is not writable."));
379 			}
380 			try {
381 				final Class<?> propertyType = propertyDescriptor
382 						.getPropertyType();
383 				if (value == null && propertyType.isPrimitive()) {
384 					method.invoke(target, PRIMITIVE_TYPE_DEFAULT_VALUES
385 							.get(propertyType));
386 				} else {
387 					method.invoke(target, value);
388 				}
389 			} catch (final IllegalArgumentException e) {
390 				throw new IllegalAttributeException(clazz, propertyDescriptor
391 						.getName(), e);
392 			} catch (final IllegalAccessException e) {
393 				throw new IllegalAttributeException(clazz, propertyDescriptor
394 						.getName(), e);
395 			} catch (final InvocationTargetException e) {
396 				final Throwable t = e.getTargetException();
397 				if (t instanceof Error) {
398 					throw (Error) t;
399 				}
400 				throw new IllegalAttributeException(clazz, propertyDescriptor
401 						.getName(), e);
402 			}
403 		}
404 
405 		/**
406 		 * {@inheritDoc}
407 		 */
408 		public ParameterizedClassDesc getParameterizedClassDesc() {
409 			return parameterizedClassDesc;
410 		}
411 
412 		/**
413 		 * {@inheritDoc}
414 		 * <p>
415 		 * 以下の順序でプロパティのメソッドの定義を検索し、最初に見つかったアノテーションを返します。
416 		 * <ol>
417 		 * <li>プロパティ値の読み込みに使用するメソッド</li>
418 		 * <li>プロパティ値の書き込みに使用するメソッド</li>
419 		 * </ol>
420 		 * </p>
421 		 * <p>
422 		 * また、クラスが {@link Proxy}
423 		 * になどよって動的に生成されている場合などは、メソッドからアノテーションを取得することができません。 (アノテーションが
424 		 * {@link Inherited} で修飾されている場合でも取得できません。)
425 		 * そのため、読み込み/書き込みメソッドの定義を以下のように検索し、アノテーションを取得します。
426 		 * <ul>
427 		 * <li>読み込み/書き込みメソッドが定義されたクラス ({@link Method#getDeclaringClass()})
428 		 * を検索対象クラスの起点とします。</li>
429 		 * <li>検索対象クラスと、そのインターフェイスから読み込み/書き込みメソッドの定義を検索します。
430 		 * <li>アノテーションが取得できなかった場合は、検索対象クラスをそのスーパークラスとし、再度検索を行います。</li>
431 		 * </ul>
432 		 * </p>
433 		 */
434 		public <T extends Annotation> T getAnnotation(
435 				final Class<T> annotationClass) {
436 			if (annotationCache.containsKey(annotationClass)) {
437 				return annotationClass.cast(annotationCache
438 						.get(annotationClass));
439 			}
440 
441 			final Method readMethod = propertyDescriptor.getReadMethod();
442 			if (readMethod != null) {
443 				final T annotation = findAnnotation(annotationClass, readMethod);
444 				if (annotation != null) {
445 					annotationCache.put(annotationClass, annotation);
446 					return annotation;
447 				}
448 			}
449 
450 			final Method writeMethod = propertyDescriptor.getWriteMethod();
451 			if (writeMethod != null) {
452 				final T annotation = findAnnotation(annotationClass,
453 						writeMethod);
454 				if (annotation != null) {
455 					annotationCache.put(annotationClass, annotation);
456 					return annotation;
457 				}
458 			}
459 
460 			annotationCache.put(annotationClass, null);
461 			return null;
462 		}
463 
464 		/**
465 		 * 指定されたメソッドのアノテーションを検索します。
466 		 * <p>
467 		 * インターフェイスやスーパークラスに定義されたメソッドの定義からもアノテーションが見つかるまで検索します。
468 		 * アノテーションが見つからなかった場合は <code>null</code> を返します。
469 		 * </p>
470 		 * 
471 		 * @param <T>
472 		 *            アノテーションの型
473 		 * @param annotationClass
474 		 *            アノテーションの型
475 		 * @param method
476 		 *            メソッド
477 		 * @return アノテーションが見つかった場合はそのアノテーション、見つからなかった場合は <code>null</code>
478 		 */
479 		private static <T extends Annotation> T findAnnotation(
480 				final Class<T> annotationClass, final Method method) {
481 			final String methodName = method.getName();
482 			final Class<?>[] parameterTypes = method.getParameterTypes();
483 			for (Class<?> target = method.getDeclaringClass(); !target
484 					.equals(Object.class); target = target.getSuperclass()) {
485 				final T annotation = getAnnotation(annotationClass, target,
486 						methodName, parameterTypes);
487 				if (annotation != null) {
488 					return annotation;
489 				}
490 				final T annotationOfInterfaces = getAnnotationOfInterfaces(
491 						annotationClass, target, methodName, parameterTypes);
492 				if (annotationOfInterfaces != null) {
493 					return annotationOfInterfaces;
494 				}
495 			}
496 			return null;
497 		}
498 
499 		/**
500 		 * 指定されたクラスが実装するインターフェイスにメソッド名、パラメータ型でシグニチャを指定されたメソッドが定義されていれば、
501 		 * そのメソッドに定義されたアノテーションを返します。
502 		 * 
503 		 * @param <T>
504 		 *            アノテーションの型
505 		 * @param annotationClass
506 		 *            アノテーションの型
507 		 * @param clazz
508 		 *            クラス
509 		 * @param methodName
510 		 *            メソッド名
511 		 * @param parameterTypes
512 		 *            パラメータの型
513 		 * @return アノテーション
514 		 */
515 		private static <T extends Annotation> T getAnnotationOfInterfaces(
516 				final Class<T> annotationClass, final Class<?> clazz,
517 				final String methodName, final Class<?>[] parameterTypes) {
518 			for (final Class<?> interfaceClass : clazz.getInterfaces()) {
519 				final T annotation = getAnnotation(annotationClass,
520 						interfaceClass, methodName, parameterTypes);
521 				if (annotation != null) {
522 					return annotation;
523 				}
524 			}
525 			return null;
526 		}
527 
528 		/**
529 		 * 指定されたクラスにメソッド名、パラメータ型でシグニチャを指定されたメソッドが定義されていれば、
530 		 * そのメソッドに定義されたアノテーションを返します。
531 		 * 
532 		 * @param <T>
533 		 *            アノテーションの型
534 		 * @param annotationClass
535 		 *            アノテーションの型
536 		 * @param clazz
537 		 *            クラス
538 		 * @param methodName
539 		 *            メソッド名
540 		 * @param parameterTypes
541 		 *            パラメータの型
542 		 * @return アノテーション
543 		 */
544 		private static <T extends Annotation> T getAnnotation(
545 				final Class<T> annotationClass, final Class<?> clazz,
546 				final String methodName,
547 				@SuppressWarnings("unchecked") final Class[] parameterTypes) {
548 			try {
549 				final Method method = clazz.getDeclaredMethod(methodName,
550 						parameterTypes);
551 				if (method.isAnnotationPresent(annotationClass)) {
552 					return method.getAnnotation(annotationClass);
553 				}
554 			} catch (final NoSuchMethodException e) {
555 				// do nothing
556 			}
557 
558 			return null;
559 		}
560 
561 		/**
562 		 * {@inheritDoc}
563 		 */
564 		public boolean isAnnotationPresent(
565 				final Class<? extends Annotation> annotationClass) {
566 			return this.getAnnotation(annotationClass) != null;
567 		}
568 
569 		/**
570 		 * {@inheritDoc}
571 		 */
572 		@Override
573 		public int hashCode() {
574 			final int prime = 31;
575 			int result = 1;
576 			result = prime
577 					* result
578 					+ ((propertyDescriptor == null) ? 0 : propertyDescriptor
579 							.hashCode());
580 			return result;
581 		}
582 
583 		/**
584 		 * {@inheritDoc}
585 		 */
586 		@Override
587 		public boolean equals(final Object obj) {
588 			if (this == obj) {
589 				return true;
590 			}
591 			if (obj == null) {
592 				return false;
593 			}
594 			if (getClass() != obj.getClass()) {
595 				return false;
596 			}
597 			final PropertyAttribute other = (PropertyAttribute) obj;
598 			if (propertyDescriptor == null) {
599 				if (other.propertyDescriptor != null) {
600 					return false;
601 				}
602 			} else if (!propertyDescriptor.equals(other.propertyDescriptor)) {
603 				return false;
604 			}
605 			return true;
606 		}
607 
608 	}
609 
610 	/**
611 	 * フィールドに対する {@link Attribute} の実装です。
612 	 * 
613 	 * @author baba
614 	 */
615 	protected static class FieldAttribute implements Attribute {
616 
617 		/** 操作対象のクラス。 */
618 		private final Class<?> clazz;
619 
620 		/** フィールド。 */
621 		private final Field field;
622 
623 		/** この属性が書き込み可能か。 */
624 		private final boolean writable;
625 
626 		/** パラメタ化されたクラスの記述。 */
627 		private final ParameterizedClassDesc parameterizedClassDesc;
628 
629 		/**
630 		 * インスタンス化します。
631 		 * 
632 		 * @param clazz
633 		 *            操作対象のクラス
634 		 * @param field
635 		 *            フィールド
636 		 */
637 		public FieldAttribute(final Class<?> clazz, final Field field) {
638 			this.clazz = clazz;
639 			this.field = field;
640 			this.writable = (field.getModifiers() & Modifier.FINAL) == 0;
641 			this.parameterizedClassDesc = createParameterizedClassDesc(field
642 					.getGenericType());
643 		}
644 
645 		/**
646 		 * {@inheritDoc}
647 		 */
648 		public String getName() {
649 			return field.getName();
650 		}
651 
652 		/**
653 		 * {@inheritDoc}
654 		 */
655 		public Class<?> getType() {
656 			return field.getType();
657 		}
658 
659 		/**
660 		 * {@inheritDoc}
661 		 */
662 		public Object getValue(final Object target) {
663 			try {
664 				if (this.isReadable() && !field.isAccessible()) {
665 					field.setAccessible(true);
666 					final Object value = field.get(target);
667 					field.setAccessible(false);
668 					return value;
669 				} else {
670 					final Object value = field.get(target);
671 					return value;
672 				}
673 			} catch (final IllegalAccessException e) {
674 				throw new IllegalAttributeException(clazz, field.getName(), e);
675 			}
676 		}
677 
678 		/**
679 		 * {@inheritDoc}
680 		 */
681 		public void setValue(final Object target, final Object value) {
682 			try {
683 				if (this.isWritable() && !field.isAccessible()) {
684 					field.setAccessible(true);
685 					field.set(target, value);
686 					field.setAccessible(false);
687 				} else {
688 					field.set(target, value);
689 				}
690 			} catch (final IllegalAccessException e) {
691 				throw new IllegalAttributeException(clazz, field.getName(), e);
692 			}
693 		}
694 
695 		/**
696 		 * {@inheritDoc}
697 		 */
698 		public boolean isReadable() {
699 			return true;
700 		}
701 
702 		/**
703 		 * {@inheritDoc}
704 		 */
705 		public boolean isWritable() {
706 			return writable;
707 		}
708 
709 		/**
710 		 * {@inheritDoc}
711 		 */
712 		public ParameterizedClassDesc getParameterizedClassDesc() {
713 			return parameterizedClassDesc;
714 		}
715 
716 		/**
717 		 * {@inheritDoc}
718 		 */
719 		public <T extends Annotation> T getAnnotation(
720 				final Class<T> annotationClass) {
721 			return field.getAnnotation(annotationClass);
722 		}
723 
724 		/**
725 		 * {@inheritDoc}
726 		 */
727 		public boolean isAnnotationPresent(
728 				final Class<? extends Annotation> annotationClass) {
729 			return field.isAnnotationPresent(annotationClass);
730 		}
731 
732 		/**
733 		 * {@inheritDoc}
734 		 */
735 		@Override
736 		public int hashCode() {
737 			final int prime = 31;
738 			int result = 1;
739 			result = prime * result + ((field == null) ? 0 : field.hashCode());
740 			return result;
741 		}
742 
743 		/**
744 		 * {@inheritDoc}
745 		 */
746 		@Override
747 		public boolean equals(final Object obj) {
748 			if (this == obj) {
749 				return true;
750 			}
751 			if (obj == null) {
752 				return false;
753 			}
754 			if (getClass() != obj.getClass()) {
755 				return false;
756 			}
757 			final FieldAttribute other = (FieldAttribute) obj;
758 			if (field == null) {
759 				if (other.field != null) {
760 					return false;
761 				}
762 			} else if (!field.equals(other.field)) {
763 				return false;
764 			}
765 			return true;
766 		}
767 
768 	}
769 
770 	/**
771 	 * {@link ParameterizedClassDesc}の実装クラスです。
772 	 * 
773 	 * @author baba
774 	 */
775 	protected static class ParameterizedClassDescImpl implements
776 			ParameterizedClassDesc {
777 
778 		/** 原型となるクラス */
779 		protected Class<?> rawClass;
780 
781 		/** 型引数を表す{@link ParameterizedClassDesc}の配列 */
782 		protected ParameterizedClassDesc[] arguments;
783 
784 		/**
785 		 * インスタンスを構築します。
786 		 */
787 		public ParameterizedClassDescImpl() {
788 		}
789 
790 		/**
791 		 * インスタンスを構築します。
792 		 * 
793 		 * @param rawClass
794 		 *            原型となるクラス
795 		 */
796 		public ParameterizedClassDescImpl(final Class<?> rawClass) {
797 			this.rawClass = rawClass;
798 		}
799 
800 		/**
801 		 * インスタンスを構築します。
802 		 * 
803 		 * @param rawClass
804 		 *            原型となるクラス
805 		 * @param arguments
806 		 *            型引数を表す{@link ParameterizedClassDesc}の配列
807 		 */
808 		public ParameterizedClassDescImpl(final Class<?> rawClass,
809 				final ParameterizedClassDesc[] arguments) {
810 			this.rawClass = rawClass;
811 			this.arguments = arguments;
812 		}
813 
814 		/**
815 		 * {@inheritDoc}
816 		 */
817 		public boolean isParameterizedClass() {
818 			return arguments != null;
819 		}
820 
821 		/**
822 		 * {@inheritDoc}
823 		 */
824 		public Class<?> getRawClass() {
825 			return rawClass;
826 		}
827 
828 		/**
829 		 * {@inheritDoc}
830 		 */
831 		public ParameterizedClassDesc[] getArguments() {
832 			return arguments;
833 		}
834 
835 	}
836 
837 	/**
838 	 * {@link Type}を表現する{@link ParameterizedClassDesc}を作成して返します。
839 	 * 
840 	 * @param type
841 	 *            型
842 	 * @return 型を表現する{@link ParameterizedClassDesc}
843 	 */
844 	protected static ParameterizedClassDesc createParameterizedClassDesc(
845 			final Type type) {
846 		final Class<?> rowClass = getRawClass(type);
847 		if (rowClass == null) {
848 			return null;
849 		}
850 		final Type[] parameterTypes = getGenericParameter(type);
851 		if (parameterTypes == null) {
852 			final ParameterizedClassDescImpl desc = new ParameterizedClassDescImpl(
853 					rowClass);
854 			return desc;
855 		} else {
856 			final ParameterizedClassDesc[] parameterDescs = new ParameterizedClassDesc[parameterTypes.length];
857 			for (int i = 0; i < parameterTypes.length; ++i) {
858 				parameterDescs[i] = createParameterizedClassDesc(parameterTypes[i]);
859 			}
860 			final ParameterizedClassDescImpl desc = new ParameterizedClassDescImpl(
861 					rowClass, parameterDescs);
862 			return desc;
863 		}
864 	}
865 
866 	/**
867 	 * <code>type</code>の原型を返します。
868 	 * <p>
869 	 * <code>type</code>が原型でもパラメータ化された型でもない場合は<code>null</code>を返します。
870 	 * </p>
871 	 * 
872 	 * @param type
873 	 *            タイプ
874 	 * @return <code>type</code>の原型
875 	 */
876 	protected static Class<?> getRawClass(final Type type) {
877 		if (Class.class.isInstance(type)) {
878 			return Class.class.cast(type);
879 		}
880 		if (ParameterizedType.class.isInstance(type)) {
881 			final ParameterizedType parameterizedType = ParameterizedType.class
882 					.cast(type);
883 			return getRawClass(parameterizedType.getRawType());
884 		}
885 		if (GenericArrayType.class.isInstance(type)) {
886 			final GenericArrayType genericArrayType = GenericArrayType.class
887 					.cast(type);
888 			final Class<?> rawClass = getRawClass(genericArrayType
889 					.getGenericComponentType());
890 			return Array.newInstance(rawClass, 0).getClass();
891 		}
892 		return null;
893 	}
894 
895 	/**
896 	 * <code>type</code>の型引数の配列を返します。
897 	 * <p>
898 	 * <code>type</code>がパラメータ化された型でない場合は<code>null</code>を返します。
899 	 * </p>
900 	 * 
901 	 * @param type
902 	 *            タイプ
903 	 * @return <code>type</code>の型引数の配列
904 	 */
905 	protected static Type[] getGenericParameter(final Type type) {
906 		if (ParameterizedType.class.isInstance(type)) {
907 			return ParameterizedType.class.cast(type).getActualTypeArguments();
908 		}
909 		if (GenericArrayType.class.isInstance(type)) {
910 			return getGenericParameter(GenericArrayType.class.cast(type)
911 					.getGenericComponentType());
912 		}
913 		return null;
914 	}
915 
916 }