EnumFormatter.java

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

  2. import java.lang.reflect.Method;
  3. import java.util.Collections;
  4. import java.util.EnumSet;
  5. import java.util.HashMap;
  6. import java.util.LinkedHashMap;
  7. import java.util.Map;
  8. import java.util.Optional;

  9. import com.gh.mygreen.xlsmapper.util.ArgUtils;

  10. /**
  11.  * 列挙型のフォーマッタ。
  12.  *
  13.  * @since 2.0
  14.  * @author T.TSUCHIE
  15.  *
  16.  * @param <T> 列挙型
  17.  */
  18. public class EnumFormatter<T extends Enum<T>> implements TextFormatter<T> {

  19.     private final Class<? extends Enum<?>> type;

  20.     private final boolean ignoreCase;

  21.     private final Optional<Method> aliasMethod;

  22.     /**
  23.      * キーが列挙型、値が文字列のマップ。
  24.      */
  25.     private final Map<Enum<?>, String> toStringMap;

  26.     /**
  27.      * キーが文字列、値が列挙型のマップ
  28.      */
  29.     private final Map<String, Enum<?>> toObjectMap;

  30.     public EnumFormatter(final Class<T> type, final boolean ignoreCase) {
  31.         ArgUtils.notNull(type, "type");

  32.         this.type = type;
  33.         this.ignoreCase = ignoreCase;
  34.         this.aliasMethod = Optional.empty();

  35.         this.toStringMap = createToStringMap(type);
  36.         this.toObjectMap = createToObjectMap(type, ignoreCase);
  37.     }

  38.     public EnumFormatter(final Class<T> type, final boolean ignoreCase, final String alias) {
  39.         ArgUtils.notNull(type, "type");
  40.         ArgUtils.notEmpty(alias, "alias");

  41.         this.type = type;
  42.         this.ignoreCase = ignoreCase;
  43.         this.aliasMethod = Optional.of(getEnumAliasMethod(type, alias));

  44.         this.toStringMap = createToStringMap(type, alias);
  45.         this.toObjectMap = createToObjectMap(type, ignoreCase, alias);

  46.     }

  47.     public EnumFormatter(final Class<T> type) {
  48.         this(type, false);
  49.     }

  50.     public EnumFormatter(final Class<T> type, final String alias) {
  51.         this(type, false, alias);
  52.     }

  53.     private static <T extends Enum<T>> Method getEnumAliasMethod(final Class<T> enumClass, final String alias) {

  54.         try {
  55.             final Method method = enumClass.getMethod(alias);
  56.             method.setAccessible(true);
  57.             return method;

  58.         } catch (ReflectiveOperationException e) {
  59.             throw new IllegalArgumentException(String.format("not found method '%s'", alias), e);
  60.         }

  61.     }

  62.     private static <T extends Enum<T>> Map<Enum<?>, String> createToStringMap(final Class<T> enumClass) {

  63.         final EnumSet<T> set = EnumSet.allOf(enumClass);

  64.         final Map<Enum<?>, String> map = new LinkedHashMap<>();
  65.         for(T e : set) {
  66.             map.put(e, e.name());

  67.         }

  68.         return Collections.unmodifiableMap(map);
  69.     }

  70.     private static <T extends Enum<T>> Map<Enum<?>, String> createToStringMap(final Class<T> enumClass, final String alias) {

  71.         final Method method = getEnumAliasMethod(enumClass, alias);

  72.         final Map<Enum<?>, String> map = new LinkedHashMap<>();
  73.         try {
  74.             final EnumSet<T> set = EnumSet.allOf(enumClass);
  75.             for(T e : set) {
  76.                 Object returnValue = method.invoke(e);
  77.                 map.put(e, returnValue.toString());

  78.             }

  79.         } catch(ReflectiveOperationException e) {
  80.             throw new RuntimeException("fail get enum value.", e);
  81.         }

  82.         return Collections.unmodifiableMap(map);
  83.     }

  84.     private static <T extends Enum<T>> Map<String, Enum<?>> createToObjectMap(final Class<T> enumClass, final boolean ignoreCase) {

  85.         final EnumSet<T> set = EnumSet.allOf(enumClass);

  86.         final Map<String, Enum<?>> map = new LinkedHashMap<>();
  87.         for(T e : set) {
  88.             final String key = (ignoreCase ? e.name().toLowerCase() : e.name());
  89.             map.put(key, e);

  90.         }

  91.         return Collections.unmodifiableMap(map);
  92.     }

  93.     private static <T extends Enum<T>> Map<String, Enum<?>> createToObjectMap(final Class<T> enumClass, final boolean ignoreCase,
  94.             final String alias) {

  95.         final Method method = getEnumAliasMethod(enumClass, alias);

  96.         final Map<String, Enum<?>> map = new LinkedHashMap<>();
  97.         try {

  98.             EnumSet<T> set = EnumSet.allOf(enumClass);
  99.             for(T e : set) {
  100.                 Object returnValue = method.invoke(e);
  101.                 final String key = (ignoreCase ? returnValue.toString().toLowerCase() : returnValue.toString());

  102.                 map.put(key, e);
  103.             }

  104.         } catch(ReflectiveOperationException e) {
  105.             throw new RuntimeException(e);
  106.         }

  107.         return Collections.unmodifiableMap(map);
  108.     }

  109.     @SuppressWarnings("unchecked")
  110.     @Override
  111.     public T parse(final String text) throws TextParseException {
  112.         final String keyText = ignoreCase ? text.toLowerCase() : text;
  113.         final Optional<T> obj = Optional.ofNullable((T)toObjectMap.get(keyText));

  114.         return obj.orElseThrow(() -> {

  115.             final Map<String, Object> vars = new HashMap<>();
  116.             vars.put("type", getType().getName());
  117.             vars.put("ignoreCase", isIgnoreCase());

  118.             getAliasMethod().ifPresent(method -> vars.put("alias", method.getName()));
  119.             vars.put("enums", getToStringMap().values());

  120.             return new TextParseException(text, type, vars);
  121.         });
  122.     }

  123.     @Override
  124.     public String format(final T value) {
  125.         final Optional<String> text = Optional.ofNullable(toStringMap.get(value));
  126.         return text.orElseGet(() -> value.toString());
  127.     }

  128.     public Class<? extends Enum<?>> getType() {
  129.         return type;
  130.     }

  131.     public boolean isIgnoreCase() {
  132.         return ignoreCase;
  133.     }

  134.     public Optional<Method> getAliasMethod() {
  135.         return aliasMethod;
  136.     }

  137.     public Map<Enum<?>, String> getToStringMap() {
  138.         return toStringMap;
  139.     }

  140.     public Map<String, Enum<?>> getToObjectMap() {
  141.         return toObjectMap;
  142.     }

  143. }