AnnotationReader.java
package com.gh.mygreen.xlsmapper.xml;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import com.gh.mygreen.xlsmapper.xml.bind.AnnotationInfo;
import com.gh.mygreen.xlsmapper.xml.bind.ClassInfo;
import com.gh.mygreen.xlsmapper.xml.bind.FieldInfo;
import com.gh.mygreen.xlsmapper.xml.bind.MethodInfo;
import com.gh.mygreen.xlsmapper.xml.bind.AnnotationMappingInfo;
/**
* フィールド、メソッドのアノテーションへアクセスするためのクラス。
* <p>Javaソースに直接アノテーションを付与する場合と、XMLで定義する方法の両方をサポートする。
*
* @version 2.0
* @author Naoki Takezoe
* @author T.TSUCHIE
*
*/
public class AnnotationReader {
/**
* XMLで定義した情報。
* nullでもよい。
*/
private final AnnotationMappingInfo xmlInfo;
/**
* アノテーションを動的に組み立てるクラス。
*/
private DynamicAnnotationBuilder annotationBuilder = DynamicAnnotationBuilder.getInstance();
/**
* XMLで定義した情報を指定するコンストラクタ。
* @param xmlInfo XMLで定義したアノテーションの情報。{@link XmlIO}で読み込んで取得した値。指定しない場合はnull。
*/
public AnnotationReader(final AnnotationMappingInfo xmlInfo) {
this.xmlInfo = xmlInfo;
}
/**
* Returns all class annotations.
*
* @param clazz the target class
* @return all annotations present on target class
* @throws AnnotationReadException
*/
public Annotation[] getAnnotations(final Class<?> clazz) throws AnnotationReadException {
if(xmlInfo != null && xmlInfo.containsClassInfo(clazz.getName())) {
final ClassInfo classInfo = xmlInfo.getClassInfo(clazz.getName());
final Map<String, Annotation> map = new HashMap<>();
if(classInfo.isOverride()) {
for(Annotation ann : clazz.getAnnotations()) {
map.put(ann.annotationType().getName(), ann);
}
}
for(AnnotationInfo annInfo: classInfo.getAnnotationInfos()) {
try {
map.put(annInfo.getClassName(),
annotationBuilder.buildAnnotation(Class.forName(annInfo.getClassName()), annInfo));
} catch (ClassNotFoundException e) {
throw new AnnotationReadException(String.format("not found class '%s'", annInfo.getClassName()), e);
}
}
return map.values().toArray(new Annotation[map.size()]);
}
return clazz.getAnnotations();
}
/**
* Returns a class annotation for the specified type if such an annotation is present, else null.
*
* @param <A> the type of the annotation
* @param clazz the target class
* @param annClass the Class object corresponding to the annotation type
* @return the target class's annotation for the specified annotation type if present on this element, else null
* @throws AnnotationReadException
*/
@SuppressWarnings("unchecked")
public <A extends Annotation> A getAnnotation(final Class<?> clazz, final Class<A> annClass) throws AnnotationReadException {
if(xmlInfo != null && xmlInfo.containsClassInfo(clazz.getName())) {
final ClassInfo classInfo = xmlInfo.getClassInfo(clazz.getName());
if(classInfo.containsAnnotationInfo(annClass.getName())) {
AnnotationInfo annInfo = classInfo.getAnnotationInfo(annClass.getName());
try {
return (A)annotationBuilder.buildAnnotation(Class.forName(annInfo.getClassName()), annInfo);
} catch (ClassNotFoundException e) {
throw new AnnotationReadException(String.format("not found class '%s'", annInfo.getClassName()), e);
}
}
}
return clazz.getAnnotation(annClass);
}
/**
* メソッドに付与された指定したアノテーションを取得する。
*
* @param method 取得対象のメソッド。
* @param annClas 取得対象のアノテーションのタイプ。
* @return
* @throws AnnotationReadException
*/
@SuppressWarnings("unchecked")
public <A extends Annotation> A getAnnotation(final Method method, final Class<A> annClas) throws AnnotationReadException {
final Class<?> clazz = method.getDeclaringClass();
if(xmlInfo != null && xmlInfo.containsClassInfo(clazz.getName())) {
final ClassInfo classInfo = xmlInfo.getClassInfo(clazz.getName());
if(classInfo.containsMethodInfo(method.getName())) {
MethodInfo methodInfo = classInfo.getMethodInfo(method.getName());
if(methodInfo != null && methodInfo.containsAnnotationInfo(annClas.getName())) {
AnnotationInfo annInfo = methodInfo.getAnnotationInfo(annClas.getName());
try {
return (A)annotationBuilder.buildAnnotation(Class.forName(annInfo.getClassName()), annInfo);
} catch (ClassNotFoundException e) {
throw new AnnotationReadException(String.format("not found class '%s'", annInfo.getClassName()), e);
}
}
}
}
return method.getAnnotation(annClas);
}
/**
* メソッドに付与されたアノテーションを持つか判定します。
* @since 2.0
* @param method 判定対象のメソッド
* @param annClass アノテーションのタイプ
* @return trueの場合、アノテーションを持ちます。
*/
public <A extends Annotation> boolean hasAnnotation(final Method method, final Class<A> annClass) {
return getAnnotation(method, annClass) != null;
}
/**
* メソッドに付与されたアノテーションを全て取得する。
*
* @param method 取得対象のメソッド。
* @return 取得対象のアノテーションのタイプ。
* @throws AnnotationReadException
*/
public Annotation[] getAnnotations(final Method method) throws AnnotationReadException {
final Class<?> clazz = method.getDeclaringClass();
if(xmlInfo != null && xmlInfo.containsClassInfo(clazz.getName())) {
final ClassInfo classInfo = xmlInfo.getClassInfo(clazz.getName());
if(classInfo.containsMethodInfo(method.getName())) {
final MethodInfo methodInfo = classInfo.getMethodInfo(method.getName());
final Map<String, Annotation> map = new HashMap<>();
if(methodInfo.isOverride()) {
for(Annotation ann : method.getAnnotations()) {
map.put(ann.annotationType().getName(), ann);
}
}
for(AnnotationInfo annInfo: methodInfo.getAnnotationInfos()){
try {
map.put(annInfo.getClassName(),
annotationBuilder.buildAnnotation(Class.forName(annInfo.getClassName()), annInfo));
} catch (ClassNotFoundException e) {
throw new AnnotationReadException(String.format("not found class '%s'", annInfo.getClassName()), e);
}
}
return map.values().toArray(new Annotation[map.size()]);
}
}
return method.getAnnotations();
}
/**
* フィールドに付与されたアノテーションを指定して取得する。
* @param field 取得対象のフィールド
* @param annClass アノテーションのタイプ
* @return
* @throws AnnotationReadException
*/
@SuppressWarnings("unchecked")
public <A extends Annotation> A getAnnotation(final Field field, final Class<A> annClass) throws AnnotationReadException {
final Class<?> clazz = field.getDeclaringClass();
if(xmlInfo != null && xmlInfo.containsClassInfo(clazz.getName())) {
final ClassInfo classInfo = xmlInfo.getClassInfo(clazz.getName());
if(classInfo.containsFieldInfo(field.getName())) {
FieldInfo fieldInfo = classInfo.getFieldInfo(field.getName());
if(fieldInfo != null && fieldInfo.containsAnnotationInfo(annClass.getName())){
AnnotationInfo annInfo = fieldInfo.getAnnotationInfo(annClass.getName());
try {
return (A)annotationBuilder.buildAnnotation(Class.forName(annInfo.getClassName()), annInfo);
} catch (ClassNotFoundException e) {
throw new AnnotationReadException(String.format("not found class '%s'", annInfo.getClassName()), e);
}
}
}
}
return field.getAnnotation(annClass);
}
/**
* フィールドに付与されたアノテーションを持つか判定します。
* @since 2.0
* @param field 判定対象のフィールド
* @param annClass アノテーションのタイプ
* @return trueの場合、アノテーションを持ちます。
*/
public <A extends Annotation> boolean hasAnnotation(final Field field, final Class<A> annClass) {
return getAnnotation(field, annClass) != null;
}
/**
* フィールドに付与されたアノテーションを全て取得する。
* @param field 取得対象のフィールド
* @return
* @throws AnnotationReadException
*/
public Annotation[] getAnnotations(final Field field) throws AnnotationReadException {
final Class<?> clazz = field.getDeclaringClass();
if(xmlInfo != null && xmlInfo.containsClassInfo(clazz.getName())) {
final ClassInfo classInfo = xmlInfo.getClassInfo(clazz.getName());
if(classInfo.containsFieldInfo(field.getName())) {
final FieldInfo fieldInfo = classInfo.getFieldInfo(field.getName());
final Map<String, Annotation> map = new HashMap<>();
if(fieldInfo.isOverride()) {
for(Annotation ann : field.getAnnotations()) {
map.put(ann.annotationType().getName(), ann);
}
}
for(AnnotationInfo annInfo: fieldInfo.getAnnotationInfos()){
try {
map.put(annInfo.getClassName(),
annotationBuilder.buildAnnotation(Class.forName(annInfo.getClassName()), annInfo));
} catch (ClassNotFoundException e) {
throw new AnnotationReadException(String.format("not found class '%s'", annInfo.getClassName()), e);
}
}
return map.values().toArray(new Annotation[map.size()]);
}
}
return field.getAnnotations();
}
public DynamicAnnotationBuilder getAnnotationBuilder() {
return annotationBuilder;
}
public void setAnnotationBuilder(DynamicAnnotationBuilder annotationBuilder) {
this.annotationBuilder = annotationBuilder;
}
}