View Javadoc
1   package com.github.mygreen.supercsv.cellprocessor.format;
2   
3   import java.lang.reflect.Method;
4   import java.util.Collections;
5   import java.util.EnumSet;
6   import java.util.HashMap;
7   import java.util.LinkedHashMap;
8   import java.util.Map;
9   import java.util.Objects;
10  import java.util.Optional;
11  
12  import com.github.mygreen.supercsv.util.ArgUtils;
13  
14  /**
15   * 列挙型をフォーマットするクラス。
16   * 
17   * @since 2.0
18   * @author T.TSUCHIE
19   *
20   */
21  public class EnumFormatter<T extends Enum<T>> extends AbstractTextFormatter<T> {
22      
23      private final Class<? extends Enum<?>> type;
24      
25      private final boolean ignoreCase;
26      
27      private final Optional<Method> selectorMethod;
28      
29      /**
30       * キーが列挙型、値が文字列のマップ。
31       */
32      private final Map<Enum<?>, String> toStringMap;
33      
34      /**
35       * キーが文字列、値が列挙型のマップ
36       */
37      private final Map<String, Enum<?>> toObjectMap;
38      
39      public EnumFormatter(final Class<T> type, final boolean ignoreCase) {
40          Objects.requireNonNull(type, "type should not be null.");
41          
42          this.type = type;
43          this.ignoreCase = ignoreCase;
44          this.selectorMethod = Optional.empty();
45          
46          this.toStringMap = createToStringMap(type);
47          this.toObjectMap = createToObjectMap(type, ignoreCase);
48      }
49      
50      public EnumFormatter(final Class<T> type, final boolean ignoreCase, final String selector) {
51          Objects.requireNonNull(type, "type should not be null.");
52          ArgUtils.notEmpty(selector, "selector");
53          
54          this.type = type;
55          this.ignoreCase = ignoreCase;
56          this.selectorMethod = Optional.of(getEnumValueMethod(type, selector));
57          
58          this.toStringMap = createToStringMap(type, selector);
59          this.toObjectMap = createToObjectMap(type, ignoreCase, selector);
60          
61      }
62      
63      public EnumFormatter(final Class<T> type) {
64          this(type, false);
65      }
66      
67      public EnumFormatter(final Class<T> type, final String selector) {
68          this(type, false, selector);
69      }
70      
71      private static <T extends Enum<T>> Method getEnumValueMethod(final Class<T> enumClass, final String selector) {
72          
73          try {
74              final Method method = enumClass.getMethod(selector);
75              method.setAccessible(true);
76              return method;
77              
78          } catch (ReflectiveOperationException e) {
79              throw new IllegalArgumentException(String.format("not found method '%s'", selector), e);
80          }
81          
82      }
83      
84      private static <T extends Enum<T>> Map<Enum<?>, String> createToStringMap(final Class<T> enumClass) {
85          
86          final EnumSet<T> set = EnumSet.allOf(enumClass);
87          
88          final Map<Enum<?>, String> map = new LinkedHashMap<>();
89          for(T e : set) {
90              map.put(e, e.name());
91              
92          }
93          
94          return Collections.unmodifiableMap(map);
95      }
96      
97      private static <T extends Enum<T>> Map<Enum<?>, String> createToStringMap(final Class<T> enumClass, final String selector) {
98          
99          final Method method = getEnumValueMethod(enumClass, selector);
100         
101         final Map<Enum<?>, String> map = new LinkedHashMap<>();
102         try {
103             final EnumSet<T> set = EnumSet.allOf(enumClass);
104             for(T e : set) {
105                 Object returnValue = method.invoke(e);
106                 map.put(e, returnValue.toString());
107                 
108             }
109             
110         } catch(ReflectiveOperationException e) {
111             throw new RuntimeException("fail get enum value.", e);
112         }
113         
114         return Collections.unmodifiableMap(map);
115     }
116     
117     private static <T extends Enum<T>> Map<String, Enum<?>> createToObjectMap(final Class<T> enumClass, final boolean ignoreCase) {
118         
119         final EnumSet<T> set = EnumSet.allOf(enumClass);
120         
121         final Map<String, Enum<?>> map = new LinkedHashMap<>();
122         for(T e : set) {
123             final String key = (ignoreCase ? e.name().toLowerCase() : e.name());
124             map.put(key, e);
125             
126         }
127         
128         return Collections.unmodifiableMap(map);
129     }
130     
131     private static <T extends Enum<T>> Map<String, Enum<?>> createToObjectMap(final Class<T> enumClass, final boolean ignoreCase,
132             final String selector) {
133         
134         final Method method = getEnumValueMethod(enumClass, selector);
135         
136         final Map<String, Enum<?>> map = new LinkedHashMap<>();
137         try {
138             
139             EnumSet<T> set = EnumSet.allOf(enumClass);
140             for(T e : set) {
141                 Object returnValue = method.invoke(e);
142                 final String key = (ignoreCase ? returnValue.toString().toLowerCase() : returnValue.toString());
143                 
144                 map.put(key, e);
145             }
146             
147         } catch(ReflectiveOperationException e) {
148             throw new RuntimeException(e);
149         }
150         
151         return Collections.unmodifiableMap(map);
152     }
153     
154     @SuppressWarnings("unchecked")
155     @Override
156     public T parse(final String text) {
157         
158         final String keyText = ignoreCase ? text.toLowerCase() : text;
159         final Optional<T> obj = Optional.ofNullable((T)toObjectMap.get(keyText));
160         
161         return obj.orElseThrow(() -> new TextParseException(text, type));
162         
163     }
164     
165     @Override
166     public String print(final T object) {
167         
168         final Optional<String> text = Optional.ofNullable(toStringMap.get(object));
169         return text.orElseGet(() -> object.toString());
170     }
171     
172     public Class<? extends Enum<?>> getType() {
173         return type;
174     }
175     
176     public boolean isIgnoreCase() {
177         return ignoreCase;
178     }
179     
180     public Optional<Method> getSelectorMethod() {
181         return selectorMethod;
182     }
183     
184     public Map<Enum<?>, String> getToStringMap() {
185         return toStringMap;
186     }
187     
188     public Map<String, Enum<?>> getToObjectMap() {
189         return toObjectMap;
190     }
191     
192     @Override
193     public Map<String, Object> getMessageVariables() {
194         
195         final Map<String, Object> vars = new HashMap<>();
196         
197         vars.put("type", getType().getName());
198         vars.put("ignoreCase", isIgnoreCase());
199         
200         getSelectorMethod().ifPresent(method -> vars.put("selector", method.getName()));
201         vars.put("enums", getToStringMap().values());
202         
203         return vars;
204         
205     }
206     
207 }