View Javadoc
1   package com.github.mygreen.supercsv.validation;
2   
3   import java.util.ArrayList;
4   import java.util.Arrays;
5   import java.util.HashMap;
6   import java.util.List;
7   import java.util.Map;
8   import java.util.Objects;
9   import java.util.stream.Collectors;
10  
11  import org.supercsv.exception.SuperCsvCellProcessorException;
12  import org.supercsv.exception.SuperCsvException;
13  import org.supercsv.util.CsvContext;
14  
15  import com.github.mygreen.supercsv.builder.BeanMapping;
16  import com.github.mygreen.supercsv.builder.ColumnMapping;
17  import com.github.mygreen.supercsv.exception.SuperCsvBindingException;
18  import com.github.mygreen.supercsv.exception.SuperCsvFixedSizeException;
19  import com.github.mygreen.supercsv.exception.SuperCsvNoMatchColumnSizeException;
20  import com.github.mygreen.supercsv.exception.SuperCsvNoMatchHeaderException;
21  import com.github.mygreen.supercsv.exception.SuperCsvRowException;
22  import com.github.mygreen.supercsv.exception.SuperCsvValidationException;
23  import com.github.mygreen.supercsv.localization.MessageInterpolator;
24  import com.github.mygreen.supercsv.localization.MessageResolver;
25  import com.github.mygreen.supercsv.localization.ResourceBundleMessageResolver;
26  import com.github.mygreen.supercsv.util.Utils;
27  
28  /**
29   * {@link SuperCsvException}をメッセージに変換するクラス。
30   * 
31   * @version 2.5
32   * @author T.TSUCHIE
33   *
34   */
35  public class CsvExceptionConverter {
36      
37      private MessageResolver messageResolver = new ResourceBundleMessageResolver();
38      
39      private MessageInterpolatorerpolator.html#MessageInterpolator">MessageInterpolator messageInterpolator = new MessageInterpolator();
40      
41      private MessageCodeGeneratorCodeGenerator.html#MessageCodeGenerator">MessageCodeGenerator codeGenerator = new MessageCodeGenerator();
42      
43      public CsvExceptionConverter() {
44          
45      }
46      
47      /**
48       * 例外をエラーオブジェクトに変換し、さらに、エラーオブジェジェクトをメッセージにフォーマットする。
49       * @param exception 変換するSuperCsvの例外。
50       * @param beanMapping Beanの定義情報
51       * @return フォーマットされたメッセージ。
52       * @throws NullPointerException {@literal exception or beanMapping is null.}
53       */
54      public List<String> convertAndFormat(final SuperCsvException exception, final BeanMapping<?> beanMapping) {
55          
56          return convert(exception, beanMapping).stream()
57                  .map(error -> error.format(messageResolver, messageInterpolator))
58                  .collect(Collectors.toList());
59      }
60      
61      /**
62       * 例外をエラーオブジェクトに変換する。
63       * @param exception 変換するSuperCsvの例外。
64       * @param beanMapping Beanの定義情報
65       * @return 変換されたエラーオブジェクト。
66       * @throws NullPointerException {@literal exception or beanMapping is null.}
67       */
68      public List<CsvError> convert(final SuperCsvException exception, final BeanMapping<?> beanMapping) {
69          
70          Objects.requireNonNull(beanMapping, "beanMapping should not be null.");
71          Objects.requireNonNull(exception, "exception should not be null.");
72          
73          final List<CsvError> errors = new ArrayList<>();
74          
75          if(exception instanceof SuperCsvBindingException) {
76              errors.addAll(convert((SuperCsvBindingException) exception, beanMapping));
77              
78          } if(exception instanceof SuperCsvRowException) {
79              errors.addAll(convert((SuperCsvRowException) exception, beanMapping));
80              
81          } else if(exception instanceof SuperCsvValidationException) {
82              errors.addAll(convert((SuperCsvValidationException)exception, beanMapping));
83              
84          } else if(exception instanceof SuperCsvCellProcessorException) {
85              errors.addAll(convert((SuperCsvCellProcessorException)exception, beanMapping));
86              
87          } else if(exception instanceof SuperCsvNoMatchColumnSizeException) {
88              errors.addAll(convert((SuperCsvNoMatchColumnSizeException)exception, beanMapping));
89              
90          } else if(exception instanceof SuperCsvNoMatchHeaderException) {
91              errors.addAll(convert((SuperCsvNoMatchHeaderException)exception, beanMapping));
92              
93          } else if(exception instanceof SuperCsvFixedSizeException) {
94              errors.addAll(convert((SuperCsvFixedSizeException)exception, beanMapping));
95              
96          } else {
97              errors.addAll(convertDefault(exception, beanMapping));
98              
99          }
100         
101         return errors;
102     }
103     
104     private List<CsvError> convert(final SuperCsvBindingException exception, final BeanMapping<?> beanMapping) {
105         
106         return exception.getBindingErrors().getAllErrors();
107     }
108     
109     private List<CsvError> convert(final SuperCsvRowException exception, final BeanMapping<?> beanMapping) {
110         
111         return exception.getColumnErrors().stream()
112             .flatMap(e -> convert(e, beanMapping).stream())
113             .collect(Collectors.toList());
114         
115     }
116     
117     private List<CsvFieldError> convert(final SuperCsvValidationException exception, final BeanMapping<?> beanMapping) {
118         
119         final CsvContext context = exception.getCsvContext();
120         final int columnNumber = context.getColumnNumber();
121         
122         final ColumnMapping columnMapping = beanMapping.getColumnMapping(columnNumber)
123                 .orElseThrow(() ->  new IllegalStateException(
124                         String.format("not found column definition with umber=%d.", columnNumber)));
125                 
126         final Map<String, Object> variables = new HashMap<>();
127         variables.put("lineNumber", context.getLineNumber());
128         variables.put("rowNumber", context.getRowNumber());
129         variables.put("columnNumber", context.getColumnNumber());
130         variables.put("label", columnMapping.getLabel());
131         variables.put("validatedValue", exception.getRejectedValue());
132         variables.putAll(exception.getMessageVariables());
133         
134         final String defaultMessage = exception.getValidationMessage();
135         final String errorCode = exception.getProcessor().getClass().getSimpleName();
136         final String objectName = beanMapping.getType().getSimpleName();
137         final String fieldName = columnMapping.getName();
138         
139         // 型変換エラーのコードを生成する
140         String[] typeMismatchCodes = {};
141         if(exception.isParedError()) {
142             // パース時の型変換エラーの場合
143             typeMismatchCodes = codeGenerator.generateTypeMismatchCodes(
144                     objectName, columnMapping.getName(), columnMapping.getField().getType());
145             
146         }
147         
148         // Bean名でエラーコードを生成する
149         String[] errorCodes = codeGenerator.generateCodes(
150                 errorCode, objectName, columnMapping.getName(), columnMapping.getField().getType());
151         
152         errorCodes = Utils.concat(typeMismatchCodes, errorCodes);
153         
154         final CsvFieldError fieldError = new CsvFieldError.Builder(objectName, fieldName, errorCodes)
155                 .processingFailure(true)
156                 .variables(variables)
157                 .defaultMessage(defaultMessage)
158                 .build();
159         
160         return Arrays.asList(fieldError);
161     }
162     
163     private List<CsvFieldError> convert(final SuperCsvCellProcessorException exception, final BeanMapping<?> beanMapping) {
164         
165         final CsvContext context = exception.getCsvContext();
166         final int columnNumber = context.getColumnNumber();
167         final Object rejectedValue = context.getRowSource().get(columnNumber-1);
168         
169         final ColumnMapping columnMapping = beanMapping.getColumnMapping(columnNumber)
170                 .orElseThrow(() ->  new IllegalStateException(
171                         String.format("not found column definition with number=%d.", columnNumber)));
172                 
173         final Map<String, Object> variables = new HashMap<>();
174         variables.put("lineNumber", context.getLineNumber());
175         variables.put("rowNumber", context.getRowNumber());
176         variables.put("columnNumber", context.getColumnNumber());
177         variables.put("label", columnMapping.getLabel());
178         variables.put("validatedValue", rejectedValue);
179         
180         final String defaultMessage = exception.getMessage();
181         
182         final String errorCode = exception.getProcessor().getClass().getSimpleName();
183         final String objectName = beanMapping.getType().getSimpleName();
184         final String fieldName = columnMapping.getName();
185         
186         String[] errorCodes = codeGenerator.generateCodes(
187                 errorCode, objectName, columnMapping.getName(), columnMapping.getField().getType());
188         
189         final CsvFieldError fieldError = new CsvFieldError.Builder(objectName, fieldName, errorCodes)
190                 .processingFailure(true)
191                 .variables(variables)
192                 .defaultMessage(defaultMessage)
193                 .build();
194         
195         return Arrays.asList(fieldError);
196         
197     
198     }
199     
200     private List<CsvError> convert(final SuperCsvNoMatchColumnSizeException exception, final BeanMapping<?> beanMapping) {
201         
202         final CsvContext context = exception.getCsvContext();
203         
204         final Map<String, Object> variables = new HashMap<>();
205         variables.put("lineNumber", context.getLineNumber());
206         variables.put("rowNumber", context.getRowNumber());
207         variables.put("expectedSize", exception.getEpxpectedColumnSize());
208         variables.put("actualSize", exception.getActualColumnSize());
209         
210         final String defaultMessage = exception.getMessage();
211         
212         final String errorCode = "csvError.noMatchColumnSize";
213         final String objectName = beanMapping.getType().getSimpleName();
214         final String[] errorCodes = codeGenerator.generateCodes(errorCode, objectName);
215         
216         final CsvError error = new CsvError.Builder(objectName, errorCodes)
217                 .variables(variables)
218                 .defaultMessage(defaultMessage)
219                 .build();
220         
221         return Arrays.asList(error);
222         
223     }
224     
225     private List<CsvError> convert(final SuperCsvNoMatchHeaderException exception, final BeanMapping<?> beanMapping) {
226         
227         final CsvContext context = exception.getCsvContext();
228         
229         final Map<String, Object> variables = new HashMap<>();
230         variables.put("lineNumber", context.getLineNumber());
231         variables.put("rowNumber", context.getRowNumber());
232         variables.put("expectedHeaders", exception.getExpectedHeaders());
233         variables.put("actualHeaders", exception.getActualHeaders());
234         variables.put("joinedExpectedHeaders", String.join(", ", exception.getExpectedHeaders()));
235         variables.put("joinedActualHeaders", String.join(", ", exception.getActualHeaders()));
236         
237         final String defaultMessage = exception.getMessage();
238         
239         final String errorCode = "csvError.noMatchHeader";
240         final String objectName = beanMapping.getType().getSimpleName();
241         final String[] errorCodes = codeGenerator.generateCodes(errorCode, objectName);
242         
243         final CsvError error = new CsvError.Builder(objectName, errorCodes)
244                 .variables(variables)
245                 .defaultMessage(defaultMessage)
246                 .build();
247         
248         return Arrays.asList(error);
249         
250     }
251     
252     private List<CsvError> convert(final SuperCsvFixedSizeException exception, final BeanMapping<?> beanMapping) {
253         
254         final CsvContext context = exception.getCsvContext();
255         final int columnNumber = context.getColumnNumber();
256         
257         final ColumnMapping columnMapping = beanMapping.getColumnMapping(columnNumber)
258                 .orElseThrow(() ->  new IllegalStateException(
259                         String.format("not found column definition with umber=%d.", columnNumber)));
260         
261         final Map<String, Object> variables = new HashMap<>();
262         variables.put("lineNumber", context.getLineNumber());
263         variables.put("rowNumber", context.getRowNumber());
264         variables.put("columnNumber", context.getColumnNumber());
265         variables.put("label", columnMapping.getLabel());
266         variables.putAll(exception.getMessageVariables());
267         
268         final String defaultMessage = exception.getMessage();
269         
270         final String errorCode = exception.getMessageCode();
271         final String objectName = beanMapping.getType().getSimpleName();
272         final String[] errorCodes = codeGenerator.generateCodes(errorCode, objectName);
273         
274         final CsvError error = new CsvError.Builder(objectName, errorCodes)
275                 .variables(variables)
276                 .defaultMessage(defaultMessage)
277                 .build();
278         
279         return Arrays.asList(error);
280         
281     }
282     
283     private List<CsvError> convertDefault(final SuperCsvException exception, final BeanMapping<?> beanMapping) {
284         
285         final CsvContext context = exception.getCsvContext();
286         
287         final Map<String, Object> variables = new HashMap<>();
288         variables.put("lineNumber", context.getLineNumber());
289         variables.put("rowNumber", context.getRowNumber());
290         variables.put("columnNumber", context.getColumnNumber());
291         
292         final String defaultMessage = exception.getMessage();
293         
294         final String errorCode = "csvError";
295         final String objectName = beanMapping.getType().getSimpleName();
296         final String[] errorCodes = codeGenerator.generateCodes(errorCode, objectName);
297         
298         final CsvError error = new CsvError.Builder(objectName, errorCodes)
299                 .variables(variables)
300                 .defaultMessage(defaultMessage)
301                 .build();
302         
303         return Arrays.asList(error);
304         
305     }
306     
307     public MessageResolver getMessageResolver() {
308         return messageResolver;
309     }
310     
311     public void setMessageResolver(MessageResolver messageResolver) {
312         this.messageResolver = messageResolver;
313     }
314     
315     public MessageInterpolator getMessageInterpolator() {
316         return messageInterpolator;
317     }
318     
319     public void setMessageInterpolator(MessageInterpolator messageInterpolator) {
320         this.messageInterpolator = messageInterpolator;
321     }
322     
323     public MessageCodeGenerator getCodeGenerator() {
324         return codeGenerator;
325     }
326     
327     public void setCodeGenerator(MessageCodeGenerator codeGenerator) {
328         this.codeGenerator = codeGenerator;
329     }
330     
331 }