FieldAccessorFactory.java
- package com.gh.mygreen.xlsmapper.fieldaccessor;
- import java.lang.annotation.Annotation;
- import java.lang.reflect.Field;
- import java.lang.reflect.Method;
- import java.lang.reflect.ParameterizedType;
- import java.util.Collection;
- import java.util.Map;
- import java.util.Optional;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import com.gh.mygreen.xlsmapper.annotation.XlsArrayCells;
- import com.gh.mygreen.xlsmapper.annotation.XlsArrayColumns;
- import com.gh.mygreen.xlsmapper.annotation.XlsIterateTables;
- import com.gh.mygreen.xlsmapper.annotation.XlsLabelledArrayCells;
- import com.gh.mygreen.xlsmapper.annotation.XlsMapColumns;
- import com.gh.mygreen.xlsmapper.localization.MessageBuilder;
- import com.gh.mygreen.xlsmapper.util.ArgUtils;
- import com.gh.mygreen.xlsmapper.util.ClassUtils;
- import com.gh.mygreen.xlsmapper.util.Utils;
- import com.gh.mygreen.xlsmapper.xml.AnnotationReader;
- /**
- * {@link FieldAccessor}のインスタンスを作成するクラス。
- *
- * @version 2.1
- * @since 2.0
- * @author T.TSUCHIE
- *
- */
- public class FieldAccessorFactory {
- private static Logger log = LoggerFactory.getLogger(FieldAccessorFactory.class);
- private final AnnotationReader annoReader;
- private PositionSetterFactory positionSetterFactory = new PositionSetterFactory();
- private PositionGetterFactory positionGetterFactory = new PositionGetterFactory();
- private MapPositionSetterFactory mapPositionSetterFactory = new MapPositionSetterFactory();
- private ArrayPositionSetterFactory arrayPositionSetterFactory = new ArrayPositionSetterFactory();
- private LabelSetterFactory labelSetterFactory = new LabelSetterFactory();
- private LabelGetterFactory labelGetterFactory = new LabelGetterFactory();
- private MapLabelSetterFactory mapLabelSetterFactory = new MapLabelSetterFactory();
- private ArrayLabelSetterFactory arrayLabelSetterFactory = new ArrayLabelSetterFactory();
-
- private CommentSetterFactory commentSetterFactory = new CommentSetterFactory();
- private CommentGetterFactory commentGetterFactory = new CommentGetterFactory();
-
- private MapCommentSetterFactory mapCommentSetterFactory = new MapCommentSetterFactory();
- private MapCommentGetterFactory mapCommentGetterFactory = new MapCommentGetterFactory();
-
- private ArrayCommentSetterFactory arrayCommentSetterFactory = new ArrayCommentSetterFactory();
- private ArrayCommentGetterFactory arrayCommentGetterFactory = new ArrayCommentGetterFactory();
-
- /**
- * コンストラクタ
- * @param annoReader XMLで定義したアノテーション情報を提供するクラス。
- * @throws IllegalArgumentException {@literal annoReader == null.}
- */
- public FieldAccessorFactory(final AnnotationReader annoReader) {
- ArgUtils.notNull(annoReader, "annoReader");
- this.annoReader = annoReader;
- }
- /**
- * フィールド情報を元にインスタンスを作成する。
- * @param field フィールド
- * @return フィールド情報を元に組み立てられたインスタンス。
- * @throws IllegalArgumentException {@literal field == null.}
- */
- public FieldAccessor create(final Field field) {
- ArgUtils.notNull(field, "field");
- final FieldAccessor accessor = new FieldAccessor();
- // 共通情報の設定
- accessor.name = field.getName();
- accessor.targetType = field.getType();
- accessor.declaringClass = field.getDeclaringClass();
- // フィールド情報の設定
- setupWithFiled(accessor, field);
- // getter情報の設定
- if(ClassUtils.isPrimitiveBoolean(accessor.getType())) {
- ClassUtils.extractBooleanGetter(accessor.getDeclaringClass(), accessor.getName())
- .ifPresent(getter -> setupWithGetter(accessor, getter));
- } else {
- ClassUtils.extractGetter(accessor.getDeclaringClass(), accessor.getName(), accessor.getType())
- .ifPresent(getter -> setupWithGetter(accessor, getter));
- }
- // setter情報の設定
- ClassUtils.extractSetter(accessor.getDeclaringClass(), accessor.getName(), accessor.getType())
- .ifPresent(setter -> setupWithSetter(accessor, setter));
- // コンポーネントタイプの設定
- if(Collection.class.isAssignableFrom(accessor.getType())) {
- ParameterizedType type = (ParameterizedType) field.getGenericType();
- accessor.componentType = Optional.of((Class<?>) type.getActualTypeArguments()[0]);
- } else if(accessor.getType().isArray()) {
- accessor.componentType = Optional.of(accessor.getType().getComponentType());
- } else if(Map.class.isAssignableFrom(accessor.getType())) {
- ParameterizedType type = (ParameterizedType) field.getGenericType();
- accessor.componentType = Optional.of((Class<?>) type.getActualTypeArguments()[1]);
- }
- // 位置・ラベル情報のアクセッサの設定
- if(accessor.hasAnnotation(XlsMapColumns.class)) {
- // マップ形式の場合
- accessor.mapPositionSetter = mapPositionSetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
- accessor.mapLabelSetter = mapLabelSetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
-
- accessor.mapCommentSetter = mapCommentSetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
- accessor.mapCommentGetter = mapCommentGetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
-
- } else if(accessor.hasAnnotation(XlsArrayColumns.class)
- || accessor.hasAnnotation(XlsArrayCells.class)
- || accessor.hasAnnotation(XlsLabelledArrayCells.class)
- || accessor.hasAnnotation(XlsIterateTables.class)){
- // リストや配列形式の場合
- accessor.arrayPositionSetter = arrayPositionSetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
- accessor.arrayLabelSetter = arrayLabelSetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
-
- accessor.arrayCommentSetter = arrayCommentSetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
- accessor.arrayCommentGetter = arrayCommentGetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
- if(accessor.hasAnnotation(XlsArrayColumns.class)
- || accessor.hasAnnotation(XlsLabelledArrayCells.class)) {
- // インデックスが付いていないラベルの設定
- accessor.labelSetter = labelSetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
- }
- } else {
- // リストやMapではない通常のプロパティの場合
- accessor.positionSetter = positionSetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
- accessor.positionGetter = positionGetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
- accessor.labelSetter = labelSetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
- accessor.labelGetter = labelGetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
-
- accessor.commentSetter = commentSetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
- accessor.commentGetter = commentGetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
-
- }
- return accessor;
- }
- /**
- * メソッド情報を元にインスタンスを作成する。
- * @param method メソッド情報
- * @return メソッド情報を元に組み立てられたインスタンス。
- * @throws IllegalArgumentException {@literal method == null.}
- * @throws IllegalArgumentException {@literal methodの名称がsetterまたはgetterの書式でない場合。}
- */
- public FieldAccessor create(final Method method) {
- ArgUtils.notNull(method, "method");
- final FieldAccessor accessor = new FieldAccessor();
- final String methodName = method.getName();
- if(ClassUtils.isGetterMethod(method) || ClassUtils.isBooleanGetterMethod(method)) {
- final String propertyName;
- if(methodName.startsWith("get")) {
- propertyName = Utils.uncapitalize(methodName.substring(3));
- } else {
- propertyName = Utils.uncapitalize(methodName.substring(2));
- }
- // 共通情報の設定
- accessor.name = propertyName;
- accessor.targetType = method.getReturnType();
- accessor.declaringClass = method.getDeclaringClass();
- // getter情報の設定
- setupWithGetter(accessor, method);
- // フィールド情報の設定
- ClassUtils.extractField(accessor.getDeclaringClass(), accessor.getName(), accessor.getType())
- .ifPresent(field -> setupWithFiled(accessor, field));
- // setter情報の設定
- ClassUtils.extractSetter(accessor.getDeclaringClass(), accessor.getName(), accessor.getType())
- .ifPresent(setter -> setupWithSetter(accessor, setter));
- // コンポーネントタイプの設定
- if(Collection.class.isAssignableFrom(accessor.getType())) {
- ParameterizedType type = (ParameterizedType) method.getGenericReturnType();
- accessor.componentType = Optional.of((Class<?>) type.getActualTypeArguments()[0]);
- } else if(accessor.getType().isArray()) {
- accessor.componentType = Optional.of(accessor.getType().getComponentType());
- } else if(Map.class.isAssignableFrom(accessor.getType())) {
- ParameterizedType type = (ParameterizedType) method.getGenericReturnType();
- accessor.componentType = Optional.of((Class<?>) type.getActualTypeArguments()[1]);
- }
- } else if(ClassUtils.isSetterMethod(method)) {
- final String propertyName = Utils.uncapitalize(methodName.substring(3));
- // 共通情報の設定
- accessor.name = propertyName;
- accessor.targetType = method.getParameterTypes()[0];
- accessor.declaringClass = method.getDeclaringClass();
- // setter情報の設定
- setupWithSetter(accessor, method);
- // フィールド情報の設定
- ClassUtils.extractField(accessor.getDeclaringClass(), accessor.getName(), accessor.getType())
- .ifPresent(field -> setupWithFiled(accessor, field));
- // getter情報の設定
- if(ClassUtils.isPrimitiveBoolean(accessor.getType())) {
- ClassUtils.extractBooleanGetter(accessor.getDeclaringClass(), accessor.getName())
- .ifPresent(getter -> setupWithGetter(accessor, getter));
- } else {
- ClassUtils.extractGetter(accessor.getDeclaringClass(), accessor.getName(), accessor.getType())
- .ifPresent(getter -> setupWithGetter(accessor, getter));
- }
- // コンポーネントタイプの設定
- if(Collection.class.isAssignableFrom(accessor.getType())) {
- ParameterizedType type = (ParameterizedType) method.getGenericParameterTypes()[0];
- accessor.componentType = Optional.of((Class<?>) type.getActualTypeArguments()[0]);
- } else if(accessor.getType().isArray()) {
- accessor.componentType = Optional.of(accessor.getType().getComponentType());
- } else if(Map.class.isAssignableFrom(accessor.getType())) {
- ParameterizedType type = (ParameterizedType) method.getGenericParameterTypes()[0];
- accessor.componentType = Optional.of((Class<?>) type.getActualTypeArguments()[1]);
- }
- } else {
- throw new IllegalArgumentException(MessageBuilder.create("method.noAccessor")
- .varWithClass("className", method.getDeclaringClass())
- .var("methodName", methodName)
- .format());
- }
- // 位置・ラベル情報のアクセッサの設定
- if(accessor.hasAnnotation(XlsMapColumns.class)) {
- accessor.mapPositionSetter = mapPositionSetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
- accessor.mapLabelSetter = mapLabelSetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
- } else if(accessor.hasAnnotation(XlsArrayColumns.class)
- || accessor.hasAnnotation(XlsArrayCells.class)
- || accessor.hasAnnotation(XlsLabelledArrayCells.class)
- || accessor.hasAnnotation(XlsIterateTables.class)){
- // リストや配列形式の場合
- accessor.arrayPositionSetter = arrayPositionSetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
- accessor.arrayLabelSetter = arrayLabelSetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
- if(accessor.hasAnnotation(XlsArrayColumns.class)
- || accessor.hasAnnotation(XlsLabelledArrayCells.class)) {
- // インデックスが付いていないラベルの設定
- accessor.labelSetter = labelSetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
- }
- } else {
- // XlsMapColumnsを持たない通常のプロパティの場合
- accessor.positionSetter = positionSetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
- accessor.positionGetter = positionGetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
- accessor.labelSetter = labelSetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
- accessor.labelGetter = labelGetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
-
- accessor.commentSetter = commentSetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
- accessor.commentGetter = commentGetterFactory.create(accessor.getDeclaringClass(), accessor.getName());
- }
- return accessor;
- }
- private void setupWithFiled(final FieldAccessor accessor, final Field field) {
- accessor.targetField = Optional.of(field);
- final Annotation[] annos = annoReader.getAnnotations(field);
- for(Annotation anno : annos) {
- if(!isSupportedAnnotation(anno)) {
- continue;
- }
- final Class<? extends Annotation> annoClass = anno.annotationType();
- if(accessor.annotationMap.containsKey(annoClass)) {
- final String message = MessageBuilder.create("anno.duplicated")
- .varWithClass("classType", accessor.getDeclaringClass())
- .var("property", field.getName())
- .varWithAnno("anno", annoClass)
- .format();
- log.warn(message);
- }
- accessor.annotationMap.put(annoClass, anno);
- }
- }
- private void setupWithGetter(final FieldAccessor accessor, final Method method) {
- accessor.targetGetter = Optional.of(method);
- final Annotation[] annos = annoReader.getAnnotations(method);
- for(Annotation anno : annos) {
- if(!isSupportedAnnotation(anno)) {
- continue;
- }
- final Class<? extends Annotation> annoClass = anno.annotationType();
- if(accessor.annotationMap.containsKey(annoClass)) {
- final String message = MessageBuilder.create("anno.duplicated")
- .varWithClass("classType", accessor.getDeclaringClass())
- .var("property", method.getName() + "()")
- .varWithAnno("anno", annoClass)
- .format();
- log.warn(message);
- }
- accessor.annotationMap.put(annoClass, anno);
- }
- }
- private void setupWithSetter(final FieldAccessor accessor, final Method method) {
- accessor.targetSetter = Optional.of(method);
- final Annotation[] annos = annoReader.getAnnotations(method);
- for(Annotation anno : annos) {
- if(!isSupportedAnnotation(anno)) {
- continue;
- }
- final Class<? extends Annotation> annoClass = anno.annotationType();
- if(accessor.annotationMap.containsKey(annoClass)) {
- final String message = MessageBuilder.create("anno.duplicated")
- .varWithClass("classType", accessor.getDeclaringClass())
- .var("property", method.getName() + "(...)")
- .varWithAnno("anno", annoClass)
- .format();
- log.warn(message);
- }
- accessor.annotationMap.put(annoClass, anno);
- }
- }
- /**
- * サポートするアノテーションか判定する。
- * <p>確実に重複するJava標準のアノテーションは除外するようにします。</p>
- *
- * @param anno 判定対象のアノテーション
- * @return tureの場合、サポートします。
- */
- private boolean isSupportedAnnotation(final Annotation anno) {
- final String name = anno.annotationType().getName();
- if(name.startsWith("java.lang.annotation.")) {
- return false;
- }
- return true;
- }
- }