EnumFormatter.java
package com.github.mygreen.supercsv.cellprocessor.format;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import com.github.mygreen.supercsv.util.ArgUtils;
/**
* 列挙型をフォーマットするクラス。
*
* @since 2.0
* @author T.TSUCHIE
*
*/
public class EnumFormatter<T extends Enum<T>> extends AbstractTextFormatter<T> {
private final Class<? extends Enum<?>> type;
private final boolean ignoreCase;
private final Optional<Method> selectorMethod;
/**
* キーが列挙型、値が文字列のマップ。
*/
private final Map<Enum<?>, String> toStringMap;
/**
* キーが文字列、値が列挙型のマップ
*/
private final Map<String, Enum<?>> toObjectMap;
public EnumFormatter(final Class<T> type, final boolean ignoreCase) {
Objects.requireNonNull(type, "type should not be null.");
this.type = type;
this.ignoreCase = ignoreCase;
this.selectorMethod = Optional.empty();
this.toStringMap = createToStringMap(type);
this.toObjectMap = createToObjectMap(type, ignoreCase);
}
public EnumFormatter(final Class<T> type, final boolean ignoreCase, final String selector) {
Objects.requireNonNull(type, "type should not be null.");
ArgUtils.notEmpty(selector, "selector");
this.type = type;
this.ignoreCase = ignoreCase;
this.selectorMethod = Optional.of(getEnumValueMethod(type, selector));
this.toStringMap = createToStringMap(type, selector);
this.toObjectMap = createToObjectMap(type, ignoreCase, selector);
}
public EnumFormatter(final Class<T> type) {
this(type, false);
}
public EnumFormatter(final Class<T> type, final String selector) {
this(type, false, selector);
}
private static <T extends Enum<T>> Method getEnumValueMethod(final Class<T> enumClass, final String selector) {
try {
final Method method = enumClass.getMethod(selector);
method.setAccessible(true);
return method;
} catch (ReflectiveOperationException e) {
throw new IllegalArgumentException(String.format("not found method '%s'", selector), e);
}
}
private static <T extends Enum<T>> Map<Enum<?>, String> createToStringMap(final Class<T> enumClass) {
final EnumSet<T> set = EnumSet.allOf(enumClass);
final Map<Enum<?>, String> map = new LinkedHashMap<>();
for(T e : set) {
map.put(e, e.name());
}
return Collections.unmodifiableMap(map);
}
private static <T extends Enum<T>> Map<Enum<?>, String> createToStringMap(final Class<T> enumClass, final String selector) {
final Method method = getEnumValueMethod(enumClass, selector);
final Map<Enum<?>, String> map = new LinkedHashMap<>();
try {
final EnumSet<T> set = EnumSet.allOf(enumClass);
for(T e : set) {
Object returnValue = method.invoke(e);
map.put(e, returnValue.toString());
}
} catch(ReflectiveOperationException e) {
throw new RuntimeException("fail get enum value.", e);
}
return Collections.unmodifiableMap(map);
}
private static <T extends Enum<T>> Map<String, Enum<?>> createToObjectMap(final Class<T> enumClass, final boolean ignoreCase) {
final EnumSet<T> set = EnumSet.allOf(enumClass);
final Map<String, Enum<?>> map = new LinkedHashMap<>();
for(T e : set) {
final String key = (ignoreCase ? e.name().toLowerCase() : e.name());
map.put(key, e);
}
return Collections.unmodifiableMap(map);
}
private static <T extends Enum<T>> Map<String, Enum<?>> createToObjectMap(final Class<T> enumClass, final boolean ignoreCase,
final String selector) {
final Method method = getEnumValueMethod(enumClass, selector);
final Map<String, Enum<?>> map = new LinkedHashMap<>();
try {
EnumSet<T> set = EnumSet.allOf(enumClass);
for(T e : set) {
Object returnValue = method.invoke(e);
final String key = (ignoreCase ? returnValue.toString().toLowerCase() : returnValue.toString());
map.put(key, e);
}
} catch(ReflectiveOperationException e) {
throw new RuntimeException(e);
}
return Collections.unmodifiableMap(map);
}
@SuppressWarnings("unchecked")
@Override
public T parse(final String text) {
final String keyText = ignoreCase ? text.toLowerCase() : text;
final Optional<T> obj = Optional.ofNullable((T)toObjectMap.get(keyText));
return obj.orElseThrow(() -> new TextParseException(text, type));
}
@Override
public String print(final T object) {
final Optional<String> text = Optional.ofNullable(toStringMap.get(object));
return text.orElseGet(() -> object.toString());
}
public Class<? extends Enum<?>> getType() {
return type;
}
public boolean isIgnoreCase() {
return ignoreCase;
}
public Optional<Method> getSelectorMethod() {
return selectorMethod;
}
public Map<Enum<?>, String> getToStringMap() {
return toStringMap;
}
public Map<String, Enum<?>> getToObjectMap() {
return toObjectMap;
}
@Override
public Map<String, Object> getMessageVariables() {
final Map<String, Object> vars = new HashMap<>();
vars.put("type", getType().getName());
vars.put("ignoreCase", isIgnoreCase());
getSelectorMethod().ifPresent(method -> vars.put("selector", method.getName()));
vars.put("enums", getToStringMap().values());
return vars;
}
}