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
30
31
32
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
50
51
52
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
64
65
66
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
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 }