View Javadoc
1   package com.github.mygreen.supercsv.cellprocessor;
2   
3   import java.lang.annotation.Annotation;
4   import java.util.Collections;
5   import java.util.HashMap;
6   import java.util.List;
7   import java.util.Map;
8   import java.util.Optional;
9   import java.util.Set;
10  import java.util.stream.Collectors;
11  
12  import org.slf4j.Logger;
13  import org.slf4j.LoggerFactory;
14  import org.supercsv.cellprocessor.ift.CellProcessor;
15  
16  import com.github.mygreen.supercsv.annotation.constraint.CsvConstraint;
17  import com.github.mygreen.supercsv.builder.BuildCase;
18  import com.github.mygreen.supercsv.builder.Configuration;
19  import com.github.mygreen.supercsv.builder.FieldAccessor;
20  import com.github.mygreen.supercsv.cellprocessor.format.TextFormatter;
21  import com.github.mygreen.supercsv.util.Utils;
22  
23  /**
24   * フィールドに設定されている制約のアノテーションをハンドリングして、{@link CellProcessor}を作成する。
25   * 
26   * @since 2.0
27   * @author T.TSUCHIE
28   *
29   */
30  public class ConstraintProcessorHandler implements ProcessorFactory {
31      
32      private static Logger logger = LoggerFactory.getLogger(ConstraintProcessorHandler.class);
33      
34      private final Map<Class<? extends Annotation>, ConstraintProcessorFactory<?>> factoryMap = new HashMap<>();
35      
36      @SuppressWarnings({"rawtypes", "unchecked"})
37      @Override
38      public Optional<CellProcessor> create(final Optional<CellProcessor> processor, final FieldAccessor field,
39              final TextFormatter<?> formatter, final Configuration config, final BuildCase buildCase, final Class<?>[] groups) {
40          
41          // 制約のアノテーションを取得する
42          final List<Annotation> annos = field.getAnnotationsByGroup(groups).stream()
43                  .filter(anno -> anno.annotationType().getAnnotation(CsvConstraint.class) != null)
44                  .filter(anno -> Utils.containsBuildCase(anno, buildCase))
45                  .collect(Collectors.toList());
46          
47          Collections.reverse(annos);
48          
49          Optional<CellProcessor> cp = processor;
50          
51          for(Annotation anno : annos) {
52              
53              final CsvConstraint constraintAnno = anno.annotationType().getAnnotation(CsvConstraint.class);
54              
55              if(factoryMap.containsKey(anno.annotationType())) {
56                  // 登録済みのものから取得する。
57                  final ConstraintProcessorFactory factory = factoryMap.get(anno.annotationType());
58                  cp = factory.create(anno, cp, field, formatter, config);
59                  
60              } else if(constraintAnno.value().length > 0) {
61                  /*
62                   * アノテーション「@CsvConstraint」が指定されている場合、クラスのインスタンスを作成する。
63                   * ・定義上、複数指定可能になっているたが、先頭のクラスのみインスタンス化する。
64                   */
65                  for(Class<? extends ConstraintProcessorFactory> factoryClass : constraintAnno.value()) {
66                      final ConstraintProcessorFactory factory = 
67                              (ConstraintProcessorFactory) config.getBeanFactory().create(factoryClass);
68                      cp = factory.create(anno, cp, field, formatter, config);
69                  }
70                  
71              } else {
72                  // factoryが見つからない場合
73                  logger.warn("Not found {} with the annotation {}.", ConstraintProcessorFactory.class.getSimpleName(), anno.getClass());
74              }
75              
76          }
77          
78          return cp;
79      }
80      
81      /**
82       * アノテーションに対する{@link ConstraintProcessorFactory}を登録する。
83       *
84       * @param <A> アノテーションのタイプ
85       * @param anno 関連づけるアノテーション
86       * @param factory 制約の{@link CellProcessor}を作成する{@link ConstraintProcessorFactory}の実装。
87       */
88      public <A extends Annotation> void register(final Class<A> anno, final ConstraintProcessorFactory<A> factory) {
89          factoryMap.put(anno, factory);
90      }
91      
92      /**
93       * 登録されている{@link ConstraintProcessorFactory}情報を取得する。
94       * @return アノテーションと対応する{@link ConstraintProcessorFactory}のマップ。
95       */
96      public Set<Map.Entry<Class<? extends Annotation>, ConstraintProcessorFactory<?>>> getEntrySet() {
97          return factoryMap.entrySet();
98      }
99      
100 }