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 }