LabelSetterFactory.java

  1. package com.gh.mygreen.xlsmapper.fieldaccessor;

  2. import java.awt.Point;
  3. import java.lang.reflect.Field;
  4. import java.lang.reflect.InvocationTargetException;
  5. import java.lang.reflect.Method;
  6. import java.lang.reflect.ParameterizedType;
  7. import java.util.LinkedHashMap;
  8. import java.util.Map;
  9. import java.util.Optional;

  10. import org.slf4j.Logger;
  11. import org.slf4j.LoggerFactory;

  12. import com.gh.mygreen.xlsmapper.util.ArgUtils;
  13. import com.gh.mygreen.xlsmapper.util.CellPosition;
  14. import com.gh.mygreen.xlsmapper.util.Utils;

  15. /**
  16.  * {@link LabelSetter}のインスタンスを作成する
  17.  *
  18.  * @since 2.0
  19.  * @author T.TSUCHIE
  20.  *
  21.  */
  22. public class LabelSetterFactory {
  23.    
  24.     private static final Logger log = LoggerFactory.getLogger(LabelSetterFactory.class);
  25.    
  26.     /**
  27.      * フィールドのラベル情報を設定するためのアクセッサを作成します。
  28.      * @param beanClass フィールドが定義されているクラス情報
  29.      * @param fieldName フィールドの名称
  30.      * @return 位置情報のsetterが存在しない場合は空を返す。
  31.      * @throws IllegalArgumentException {@literal beanClass == null or fieldName == null}
  32.      * @throws IllegalArgumentException {@literal fieldName.isEmpty() = true}
  33.      */
  34.     public Optional<LabelSetter> create(final Class<?> beanClass, final String fieldName) {
  35.        
  36.         ArgUtils.notNull(beanClass, "beanClass");
  37.         ArgUtils.notEmpty(fieldName, "fieldName");
  38.        
  39.         // フィールド Map labelsの場合
  40.         Optional<LabelSetter> LabelSetter = createMapField(beanClass, fieldName);
  41.         if(LabelSetter.isPresent()) {
  42.             return LabelSetter;
  43.         }
  44.        
  45.         // setter メソッドの場合
  46.         LabelSetter = createMethod(beanClass, fieldName);
  47.         if(LabelSetter.isPresent()) {
  48.             return LabelSetter;
  49.         }
  50.        
  51.         // フィールド + labelの場合
  52.         LabelSetter = createField(beanClass, fieldName);
  53.         if(LabelSetter.isPresent()) {
  54.             return LabelSetter;
  55.         }
  56.        
  57.        
  58.         return Optional.empty();
  59.     }
  60.    
  61.     /**
  62.      * {@link Map}フィールドにラベル情報が格納されている場合。
  63.      * <p>キーはフィールド名。</p>
  64.      * <p>マップの値は、Stringをサポートする。</p>
  65.      *
  66.      * @param beanClass フィールドが定義してあるクラスのインスタンス
  67.      * @param fieldName フィールド名
  68.      * @return ラベル情報の設定用クラス
  69.      */
  70.     private Optional<LabelSetter> createMapField(final Class<?> beanClass, final String fieldName) {
  71.        
  72.         final Field labelField;
  73.         try {
  74.             labelField = beanClass.getDeclaredField("labels");
  75.             labelField.setAccessible(true);
  76.            
  77.         } catch (NoSuchFieldException | SecurityException e) {
  78.             // フィールドが見つからない場合は、何もしない。
  79.             return Optional.empty();
  80.         }
  81.        
  82.         if(!Map.class.isAssignableFrom(labelField.getType())) {
  83.             return Optional.empty();
  84.         }
  85.        
  86.         final ParameterizedType type = (ParameterizedType) labelField.getGenericType();
  87.         final Class<?> keyType = (Class<?>) type.getActualTypeArguments()[0];
  88.         final Class<?> valueType = (Class<?>) type.getActualTypeArguments()[1];
  89.        
  90.         if(keyType.equals(String.class) && valueType.equals(String.class)) {
  91.             return Optional.of(new LabelSetter() {
  92.                
  93.                 @SuppressWarnings("unchecked")
  94.                 @Override
  95.                 public void set(final Object beanObj, final String label) {
  96.                     ArgUtils.notNull(beanObj, "beanObj");
  97.                     ArgUtils.notEmpty(label, "label");
  98.                    
  99.                     try {
  100.                         Map<String, String> labelsMapObj = (Map<String, String>) labelField.get(beanObj);
  101.                         if(labelsMapObj == null) {
  102.                             labelsMapObj = new LinkedHashMap<>();
  103.                             labelField.set(beanObj, labelsMapObj);
  104.                         }
  105.                        
  106.                         labelsMapObj.put(fieldName, label);
  107.                        
  108.                     } catch (IllegalArgumentException | IllegalAccessException e) {
  109.                         throw new RuntimeException("fail access labels field.", e);
  110.                     }
  111.                 }
  112.             });
  113.            
  114.         } else {
  115.             // タイプが一致しない場合
  116.             log.warn("not match generics type of labels. key type:{}, value type:{}.", keyType.getName(), valueType.getName());
  117.             return Optional.empty();
  118.         }
  119.        
  120.     }
  121.    
  122.     /**
  123.      * setterメソッドによるラベル情報を格納する場合。
  124.      * <p>{@code set + <フィールド名> + Label}のメソッド名</p>
  125.      * <p>引数として、をサポートする。</p>
  126.      *
  127.      * @param beanClass フィールドが定義してあるクラスのインスタンス
  128.      * @param fieldName フィールド名
  129.      * @return ラベル情報の設定用クラス
  130.      */
  131.     private Optional<LabelSetter> createMethod(final Class<?> beanClass, final String fieldName) {
  132.        
  133.         final String labelMethodName = "set" + Utils.capitalize(fieldName) + "Label";
  134.        
  135.         try {
  136.             final Method method = beanClass.getDeclaredMethod(labelMethodName, String.class);
  137.             method.setAccessible(true);
  138.            
  139.             return Optional.of(new LabelSetter() {
  140.                
  141.                
  142.                 @Override
  143.                 public void set(final Object beanObj, final String label) {
  144.                     ArgUtils.notNull(beanObj, "beanObj");
  145.                     ArgUtils.notEmpty(label, "label");
  146.                    
  147.                     try {
  148.                         method.invoke(beanObj, label);
  149.                        
  150.                     } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
  151.                         throw new RuntimeException("fail access labels field.", e);
  152.                     }
  153.                    
  154.                 }
  155.             });
  156.            
  157.         } catch (NoSuchMethodException | SecurityException e) {
  158.            
  159.         }
  160.        
  161.         return Optional.empty();
  162.        
  163.     }
  164.    
  165.     /**
  166.      * フィールドによるラベル情報を格納する場合。
  167.      * <p>{@code <フィールド名> + Label}のメソッド名</p>
  168.      * <p>引数として、{@link CellPosition}、{@link Point}、 {@link org.apache.poi.ss.util.CellAddress}をサポートする。</p>
  169.      *
  170.      * @param beanClass フィールドが定義してあるクラスのインスタンス
  171.      * @param fieldName フィールド名
  172.      * @return ラベル情報の設定用クラス
  173.      */
  174.     private Optional<LabelSetter> createField(final Class<?> beanClass, final String fieldName) {
  175.        
  176.         final String labelFieldName = fieldName + "Label";
  177.        
  178.         final Field labelField;
  179.         try {
  180.             labelField = beanClass.getDeclaredField(labelFieldName);
  181.             labelField.setAccessible(true);
  182.            
  183.         } catch (NoSuchFieldException | SecurityException e) {
  184.             return Optional.empty();
  185.         }
  186.        
  187.         if(labelField.getType().equals(String.class)) {
  188.            
  189.             return Optional.of(new LabelSetter() {
  190.                
  191.                 @Override
  192.                 public void set(final Object beanObj, final String label) {
  193.                     ArgUtils.notNull(beanObj, "beanObj");
  194.                     ArgUtils.notNull(label, "label");
  195.                    
  196.                     try {
  197.                         labelField.set(beanObj, label);
  198.                     } catch (IllegalArgumentException | IllegalAccessException e) {
  199.                         throw new RuntimeException("fail access label field.", e);
  200.                     }
  201.                 }
  202.             });
  203.            
  204.         }
  205.        
  206.         return Optional.empty();
  207.     }
  208. }