MapCommentSetterFactory.java

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

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

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

  11. import com.gh.mygreen.xlsmapper.util.ArgUtils;
  12. import com.gh.mygreen.xlsmapper.util.Utils;

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