All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.mygreen.supercsv.builder.FieldAccessor Maven / Gradle / Ivy

Go to download

CSVのJavaライブラリであるSuperCSVに、アノテーション機能を追加したライブラリです。

There is a newer version: 2.3
Show newest version
package com.github.mygreen.supercsv.builder;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import org.supercsv.exception.SuperCsvReflectionException;

import com.github.mygreen.supercsv.annotation.DefaultGroup;
import com.github.mygreen.supercsv.util.Utils;

/**
 * フィールドに統一的にアクセスするためのクラス。
 *
 * @since 2.0
 * @author T.TSUCHIE
 *
 */
public class FieldAccessor {
    
    /**
     * フィールドの実体
     */
    private final Field field;
    
    /**
     * フィールドの名称
     */
    private final String name;
    
    /**
     * フィールドのタイプ
     */
    private final Class type;
    
    /**
     * アノテーションの一覧
     */
    private final List expandedAnnos = new ArrayList<>();
    
    /**
     * フィールド情報を指定するコンストラクタ。
     * @param field フィールド情報
     * @param comparator アノテーションの順序を比較するためのコンパレータ。
     * @throws NullPointerException {@literal field or comparator == null.}
     */
    public FieldAccessor(final Field field, final Comparator comparator) {
        Objects.requireNonNull(field);
        Objects.requireNonNull(comparator);
        
        field.setAccessible(true);
        
        this.field = field;
        this.type = field.getType();
        this.name = field.getName();
        
        final AnnotationExpander expander = new AnnotationExpander(comparator);
        this.expandedAnnos.addAll(expander.expand(field.getAnnotations()));
    }
    
    /**
     * アノテーションのタイプを指定してアノテーションを取得します。
     * 

繰り返しのアノテーションの場合、初めに見つかったものを返します。

* * @param 取得対象のアノテーションのタイプ * @param annoClass 取得対象のアノテーションのタイプ。 * @return 指定したアノテーションが見つからない場合は、空を返します。 * @throws NullPointerException {@literal annoClass is null.} */ public Optional getAnnotation(final Class annoClass) { Objects.requireNonNull(annoClass, "annoClass should not be null."); return getAnnotationsByType(expandedAnnos, annoClass).stream() .findFirst(); } /** * アノテーションのタイプを指定してアノテーション一覧を取得します。 *

繰り返しのアノテーションの場合、初めに見つかったものを返します。

* * @param
取得対象のアノテーションのタイプ * @param annoClass 取得対象のアノテーションのタイプ。 * @return 指定したアノテーションが見つからない場合は、空のリスト返します。 * @throws NullPointerException {@literal annoClass is null.} */ public List getAnnotations(final Class annoClass) { Objects.requireNonNull(annoClass, "annoClass should not be null."); return getAnnotationsByType(expandedAnnos, annoClass); } @SuppressWarnings({"unchecked"}) private static List getAnnotationsByType( final List expanedAnnos, final Class annoClass) { final List list = new ArrayList<>(); for(ExpandedAnnotation anno : expanedAnnos) { if(anno.isAnnotationType(annoClass)) { list.add((A)anno.getOriginal()); } else if(anno.isComposed()) { list.addAll(getAnnotationsByType(anno.getChilds(), annoClass)); } } return list; } /** * 指定したアノテーションと持つかどうか。 *

繰り返し可能なアノテーションの場合、初めに見つかったものを返します。

* * @param
取得対象のアノテーションのタイプ * @param annoClass 取得対象のアノテーションのタイプ。 * @return {@literal true}の場合、アノテーションを持ちます。 * @throws NullPointerException {@literal annoClass is null.} */ public boolean hasAnnotation(final Class annoClass) { return getAnnotation(annoClass).isPresent(); } /** * アノテーションのタイプとグループを指定してアノテーションを取得します。 * * @param 取得対象のアノテーションのタイプ * @param annoClass 取得対象のアノテーションのタイプ。 * @param groups グループ(クラスタイプ)による絞り込み。属性groupsが存在する場合に、絞り込みます。 * @return 指定したアノテーションが見つからない場合は、サイズ0のリストを返します。 * @throws NullPointerException {@literal annoClass is null.} */ public List getAnnotationsByGroup(final Class annoClass, final Class... groups) { Objects.requireNonNull(annoClass, "annoClass should not be null."); return getAnnotations(annoClass).stream() .filter(anno -> hasGroups(anno, groups)) .collect(Collectors.toList()); } /** * グループを指定して指定したアノテーションを持つかどうか判定します。 * * @param 取得対象のアノテーションのタイプ * @param annoClass 判定対象のアノテーションのグループ * @param groups グループ(クラスタイプ)による絞り込み。属性groupsが存在する場合に、絞り込みます。 * @return 指定したアノテーションが見つからない場合は、サイズ0のリストを返します。 */ public boolean hasAnnotationByGroup(final Class annoClass, final Class... groups) { return getAnnotationsByGroup(annoClass, groups).size() > 0; } /** * 付与されているアノテーションの一覧を取得する。 * * @param groups グループ(クラスタイプ)による絞り込み。属性groupsが存在する場合に、絞り込みます。 * @return 指定したアノテーションが見つからない場合は、サイズ0のリストを返します。 */ public List getAnnotationsByGroup(final Class... groups) { return getAnnotations(expandedAnnos).stream() .filter(anno -> hasGroups(anno, groups)) .collect(Collectors.toList()); } @SuppressWarnings({"unchecked"}) private static List getAnnotations(final List expanedAnnos) { final List list = new ArrayList<>(); for(ExpandedAnnotation anno : expanedAnnos) { if(anno.isComposed()) { list.addAll(getAnnotations(anno.getChilds())); } else { list.add((A)anno.getOriginal()); } } return list; } /** * アノテーションの属性{@literal groups} が指定したグループと一致するか比較します。 *

groups属性を持たない場合は、必ずfalseを返します。

* @param anno 検証対象のアノテーション。 * @param groups 比較対象のグループ情報。 * @return {@literal true}の場合、指定したグループを持ちます。 */ @SuppressWarnings("rawtypes") private boolean hasGroups(final Annotation anno, final Class... groups) { final Optional targetGroups = Utils.getAnnotationAttribute(anno, "groups", Class[].class); if(!targetGroups.isPresent()) { // groups属性を持たない場合 return false; } if(groups.length == 0) { if(targetGroups.get().length == 0) { // グループの指定がない場合は、デフォルトグループとして処理。 return true; } else { for(Class targetGroup : targetGroups.get()) { if(targetGroup.equals(DefaultGroup.class)) { // デフォルトを直接指定している場合に、グループと一致。 return true; } } } } else { // グループの指定がある場合 for(Class group : groups) { if(group.equals(DefaultGroup.class) && targetGroups.get().length == 0) { // フィールド側にグループの指定がない場合は、デフォルトグループとして処理する。 return true; } for(Class targetGroup : targetGroups.get()) { // 一致するグループを持つか判定する。 if(targetGroup.equals(group)) { return true; } } } } return false; } /** * フィールドの名称を取得する。 * @return フィールド名 */ public String getName() { return name; } /** * クラス名付きのフィールド名称を取得する。 * @return {@literal <クラス名#フィールド名>}の形式 */ public String getNameWithClass() { return getDeclaredClass().getName() + "#" + getName(); } /** * フィールドのタイプを取得する。 * @return フィールドのクラスタイプ。 */ public Class getType() { return type; } /** * フィールドのタイプのクラス名称を取得する。 * @return パッケージ名付きのFQDNの形式。 */ public String getTypeName() { return getType().getName(); } /** * フィールドが定義されているクラス情報を取得する。 * * @see Field#getDeclaringClass() * @return フィールドが定義されているクラス上方。 */ public Class getDeclaredClass() { return field.getDeclaringClass(); } /** * フィールドのタイプが指定してたタイプかどうか。 *

{@link Class#isAssignableFrom(Class)}により比較を行う。 * @param clazz 比較対象のクラスタイプ。 * @return タイプが一致する場合、{@literal true}を返す。 */ public boolean isTypeOf(final Class clazz) { return clazz.isAssignableFrom(getType()); } /** * フィールドの値を取得する。 * @param record レコードオブジェクト。 * @return フィールドの値。 * @throws IllegalArgumentException レコードのインスタンスがフィールドが定義されているクラスと異なる場合。 * @throws SuperCsvReflectionException フィールドの値の取得に失敗した場合。 */ public Object getValue(final Object record) { Objects.requireNonNull(record); if(!getDeclaredClass().equals(record.getClass())) { throw new IllegalArgumentException(String.format("not match record class type. expected=%s. actual=%s, ", type.getName(), record.getClass().getName())); } try { return field.get(record); } catch (IllegalArgumentException | IllegalAccessException e) { throw new SuperCsvReflectionException("fail get field value.", e); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy