CsvExceptionConverter.java
package com.github.mygreen.supercsv.validation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.supercsv.exception.SuperCsvCellProcessorException;
import org.supercsv.exception.SuperCsvException;
import org.supercsv.util.CsvContext;
import com.github.mygreen.supercsv.builder.BeanMapping;
import com.github.mygreen.supercsv.builder.ColumnMapping;
import com.github.mygreen.supercsv.exception.SuperCsvBindingException;
import com.github.mygreen.supercsv.exception.SuperCsvNoMatchColumnSizeException;
import com.github.mygreen.supercsv.exception.SuperCsvNoMatchHeaderException;
import com.github.mygreen.supercsv.exception.SuperCsvRowException;
import com.github.mygreen.supercsv.exception.SuperCsvValidationException;
import com.github.mygreen.supercsv.localization.MessageInterpolator;
import com.github.mygreen.supercsv.localization.MessageResolver;
import com.github.mygreen.supercsv.localization.ResourceBundleMessageResolver;
import com.github.mygreen.supercsv.util.Utils;
/**
* {@link SuperCsvException}をメッセージに変換するクラス。
*
* @version 2.0
* @author T.TSUCHIE
*
*/
public class CsvExceptionConverter {
private MessageResolver messageResolver = new ResourceBundleMessageResolver();
private MessageInterpolator messageInterpolator = new MessageInterpolator();
private MessageCodeGenerator codeGenerator = new MessageCodeGenerator();
public CsvExceptionConverter() {
}
/**
* 例外をエラーオブジェクトに変換し、さらに、エラーオブジェジェクトをメッセージにフォーマットする。
* @param exception 変換するSuperCsvの例外。
* @param beanMapping Beanの定義情報
* @return フォーマットされたメッセージ。
* @throws NullPointerException {@literal exception or beanMapping is null.}
*/
public List<String> convertAndFormat(final SuperCsvException exception, final BeanMapping<?> beanMapping) {
return convert(exception, beanMapping).stream()
.map(error -> error.format(messageResolver, messageInterpolator))
.collect(Collectors.toList());
}
/**
* 例外をエラーオブジェクトに変換する。
* @param exception 変換するSuperCsvの例外。
* @param beanMapping Beanの定義情報
* @return 変換されたエラーオブジェクト。
* @throws NullPointerException {@literal exception or beanMapping is null.}
*/
public List<CsvError> convert(final SuperCsvException exception, final BeanMapping<?> beanMapping) {
Objects.requireNonNull(beanMapping, "beanMapping should not be null.");
Objects.requireNonNull(exception, "exception should not be null.");
final List<CsvError> errors = new ArrayList<>();
if(exception instanceof SuperCsvBindingException) {
errors.addAll(convert((SuperCsvBindingException) exception, beanMapping));
} if(exception instanceof SuperCsvRowException) {
errors.addAll(convert((SuperCsvRowException) exception, beanMapping));
} else if(exception instanceof SuperCsvValidationException) {
errors.addAll(convert((SuperCsvValidationException)exception, beanMapping));
} else if(exception instanceof SuperCsvCellProcessorException) {
errors.addAll(convert((SuperCsvCellProcessorException)exception, beanMapping));
} else if(exception instanceof SuperCsvNoMatchColumnSizeException) {
errors.addAll(convert((SuperCsvNoMatchColumnSizeException)exception, beanMapping));
} else if(exception instanceof SuperCsvNoMatchHeaderException) {
errors.addAll(convert((SuperCsvNoMatchHeaderException)exception, beanMapping));
} else {
errors.addAll(convertDefault(exception, beanMapping));
}
return errors;
}
private List<CsvError> convert(final SuperCsvBindingException exception, final BeanMapping<?> beanMapping) {
return exception.getBindingErrors().getAllErrors();
}
private List<CsvError> convert(final SuperCsvRowException exception, final BeanMapping<?> beanMapping) {
return exception.getColumnErrors().stream()
.flatMap(e -> convert(e, beanMapping).stream())
.collect(Collectors.toList());
}
private List<CsvFieldError> convert(final SuperCsvValidationException exception, final BeanMapping<?> beanMapping) {
final CsvContext context = exception.getCsvContext();
final int columnNumber = context.getColumnNumber();
final ColumnMapping columnMapping = beanMapping.getColumnMapping(columnNumber)
.orElseThrow(() -> new IllegalStateException(
String.format("not found column definition with umber=%d.", columnNumber)));
final Map<String, Object> variables = new HashMap<>();
variables.put("lineNumber", context.getLineNumber());
variables.put("rowNumber", context.getRowNumber());
variables.put("columnNumber", context.getColumnNumber());
variables.put("label", columnMapping.getLabel());
variables.put("validatedValue", exception.getRejectedValue());
variables.putAll(exception.getMessageVariables());
final String defaultMessage = exception.getValidationMessage();
final String errorCode = exception.getProcessor().getClass().getSimpleName();
final String objectName = beanMapping.getType().getSimpleName();
final String fieldName = columnMapping.getName();
// 型変換エラーのコードを生成する
String[] typeMismatchCodes = {};
if(exception.isParedError()) {
// パース時の型変換エラーの場合
typeMismatchCodes = codeGenerator.generateTypeMismatchCodes(
objectName, columnMapping.getName(), columnMapping.getField().getType());
}
// Bean名でエラーコードを生成する
String[] errorCodes = codeGenerator.generateCodes(
errorCode, objectName, columnMapping.getName(), columnMapping.getField().getType());
errorCodes = Utils.concat(typeMismatchCodes, errorCodes);
final CsvFieldError fieldError = new CsvFieldError.Builder(objectName, fieldName, errorCodes)
.processingFailure(true)
.variables(variables)
.defaultMessage(defaultMessage)
.build();
return Arrays.asList(fieldError);
}
private List<CsvFieldError> convert(final SuperCsvCellProcessorException exception, final BeanMapping<?> beanMapping) {
final CsvContext context = exception.getCsvContext();
final int columnNumber = context.getColumnNumber();
final Object rejectedValue = context.getRowSource().get(columnNumber-1);
final ColumnMapping columnMapping = beanMapping.getColumnMapping(columnNumber)
.orElseThrow(() -> new IllegalStateException(
String.format("not found column definition with number=%d.", columnNumber)));
final Map<String, Object> variables = new HashMap<>();
variables.put("lineNumber", context.getLineNumber());
variables.put("rowNumber", context.getRowNumber());
variables.put("columnNumber", context.getColumnNumber());
variables.put("label", columnMapping.getLabel());
variables.put("validatedValue", rejectedValue);
final String defaultMessage = exception.getMessage();
final String errorCode = exception.getProcessor().getClass().getSimpleName();
final String objectName = beanMapping.getType().getSimpleName();
final String fieldName = columnMapping.getName();
String[] errorCodes = codeGenerator.generateCodes(
errorCode, objectName, columnMapping.getName(), columnMapping.getField().getType());
final CsvFieldError fieldError = new CsvFieldError.Builder(objectName, fieldName, errorCodes)
.processingFailure(true)
.variables(variables)
.defaultMessage(defaultMessage)
.build();
return Arrays.asList(fieldError);
}
private List<CsvError> convert(final SuperCsvNoMatchColumnSizeException exception, final BeanMapping<?> beanMapping) {
final CsvContext context = exception.getCsvContext();
final Map<String, Object> variables = new HashMap<>();
variables.put("lineNumber", context.getLineNumber());
variables.put("rowNumber", context.getRowNumber());
variables.put("expectedSize", exception.getEpxpectedColumnSize());
variables.put("actualSize", exception.getActualColumnSize());
final String defaultMessage = exception.getMessage();
final String errorCode = "csvError.noMatchColumnSize";
final String objectName = beanMapping.getType().getSimpleName();
final String[] errorCodes = codeGenerator.generateCodes(errorCode, objectName);
final CsvError error = new CsvError.Builder(objectName, errorCodes)
.variables(variables)
.defaultMessage(defaultMessage)
.build();
return Arrays.asList(error);
}
private List<CsvError> convert(final SuperCsvNoMatchHeaderException exception, final BeanMapping<?> beanMapping) {
final CsvContext context = exception.getCsvContext();
final Map<String, Object> variables = new HashMap<>();
variables.put("lineNumber", context.getLineNumber());
variables.put("rowNumber", context.getRowNumber());
variables.put("expectedHeaders", exception.getExpectedHeaders());
variables.put("actualHeaders", exception.getActualHeaders());
variables.put("joinedExpectedHeaders", String.join(", ", exception.getExpectedHeaders()));
variables.put("joinedActualHeaders", String.join(", ", exception.getActualHeaders()));
final String defaultMessage = exception.getMessage();
final String errorCode = "csvError.noMatchHeader";
final String objectName = beanMapping.getType().getSimpleName();
final String[] errorCodes = codeGenerator.generateCodes(errorCode, objectName);
final CsvError error = new CsvError.Builder(objectName, errorCodes)
.variables(variables)
.defaultMessage(defaultMessage)
.build();
return Arrays.asList(error);
}
private List<CsvError> convertDefault(final SuperCsvException exception, final BeanMapping<?> beanMapping) {
final CsvContext context = exception.getCsvContext();
final Map<String, Object> variables = new HashMap<>();
variables.put("lineNumber", context.getLineNumber());
variables.put("rowNumber", context.getRowNumber());
variables.put("columnNumber", context.getColumnNumber());
final String defaultMessage = exception.getMessage();
final String errorCode = "csvError";
final String objectName = beanMapping.getType().getSimpleName();
final String[] errorCodes = codeGenerator.generateCodes(errorCode, objectName);
final CsvError error = new CsvError.Builder(objectName, errorCodes)
.variables(variables)
.defaultMessage(defaultMessage)
.build();
return Arrays.asList(error);
}
public MessageResolver getMessageResolver() {
return messageResolver;
}
public void setMessageResolver(MessageResolver messageResolver) {
this.messageResolver = messageResolver;
}
public MessageInterpolator getMessageInterpolator() {
return messageInterpolator;
}
public void setMessageInterpolator(MessageInterpolator messageInterpolator) {
this.messageInterpolator = messageInterpolator;
}
public MessageCodeGenerator getCodeGenerator() {
return codeGenerator;
}
public void setCodeGenerator(MessageCodeGenerator codeGenerator) {
this.codeGenerator = codeGenerator;
}
}