View Javadoc

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