package com.gh.mygreen.xlsmapper.validation; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import com.gh.mygreen.xlsmapper.ArgUtils; import com.gh.mygreen.xlsmapper.Utils; /** * エラーオブジェクトを解釈して、メッセージに変換するクラス。 * <p>オブジェクトの種類ごとに、デフォルトメッセージ変数が利用できます。 * <ul> * <li>'fieldLabel':フィールドのラベル。メッセージ用のプロパティファイルにフィールド名を定義している場合、自動的に設定されます。 * <li>'objectLabel':オブジェクトのラベル。メッセージ用のプロパティファイルにオブジェクト名を定義している場合、自動的に設定されます。 * <li>'label':ラベル変数'label'が指定されていない場合、エラー対象のオブジェクト名またはフィールド名から自動的に決定されます。 * <li>'sheetName':シート用のエラーの場合、シート名が設定されます。 * <li>'cellAddress':シート用のフィールドエラーの場合、セルのアドレスが設定されます。'A1'のような形式になります。 * * * @author T.TSUCHIE * */ public class SheetMessageConverter { private MessageResolver messageResolver = new ResourceBundleMessageResolver(); private MessageInterpolator messageInterporlator = new MessageInterpolator(); private MessageCodeGenerator messageCodeGenerator = new MessageCodeGenerator(); public SheetMessageConverter() { } /** * エラーオブジェクトのリストをメッセージに変換する。 * @param errors 変換対象のエラーオブジェクト。 * @return * @throws IllegalArgumentException errors == null. */ public List<String> convertMessages(final Collection<ObjectError> errors) { ArgUtils.notNull(errors, "errors"); final List<String> messageList = new ArrayList<String>(); for(ObjectError error : errors) { messageList.add(convertMessage(error)); } return messageList; } /** * {@link ObjectError}をメッセージに変換する。 * @param error * @return * @throws IllegalArgumentException errors == null. */ public String convertMessage(final ObjectError error) { ArgUtils.notNull(error, "error"); if(error.getArgs() != null) { return convertMessageWithIndexArgs(error); } else if(error.getVars() != null) { return convertMessageWithNameArgs(error); } else { return convertMessageWithNameArgs(error); } } /** * インデックス形式の変数のメッセージとして{@link ObjectError}を変換する。 * @param error * @return */ protected String convertMessageWithIndexArgs(final ObjectError error) { final List<Object> args = new ArrayList<Object>(); if(error instanceof FieldError) { if(error.getLabel() != null) { args.add(error.getLabel()); } else { final String[] labelCode = messageCodeGenerator.generateFieldNameCodes(error.getObjectName(), ((FieldError) error).getFieldPath()); try { args.add(getMessage(labelCode, error.getDefaultMessage())); } catch(Throwable e) { // args.add(null); } } } else { final String[] labelCode = messageCodeGenerator.generateObjectNameCodes(error.getObjectName()); if(error.getLabel() != null) { args.add(error.getLabel()); } else { try { args.add(getMessage(labelCode, error.getDefaultMessage())); } catch(Throwable e) { // args.add(null); } } } if(error.getArgs() != null) { args.add(Arrays.asList(error.getArgs())); } final String message = getMessage(error.getCodes(), error.getDefaultMessage()); return MessageFormat.format(message, args.toArray(new Object[args.size()])); } /** * 名前付き変数のメッセージとして{@link ObjectError}を変換する。 * @param error * @return */ protected String convertMessageWithNameArgs(final ObjectError error) { final Map<String, Object> vars = new LinkedHashMap<String, Object>(); if(error.getVars() != null) { vars.putAll(error.getVars()); } if(error instanceof FieldError) { // フィールドエラーのメッセージを処理する final FieldError fieldError = (FieldError) error; final String[] labelCode = messageCodeGenerator.generateFieldNameCodes(fieldError.getObjectName(), fieldError.getFieldPath()); try { vars.put("fieldLabel", getMessage(labelCode, null)); } catch(Throwable e) { } if(error.getLabel() != null) { vars.put("label", error.getLabel()); } else { try { vars.put("label", getMessage(labelCode, null)); } catch(Throwable e) { } } try { // 親のラベル名を取得する String[] parentCode = messageCodeGenerator.generateParentNameCodes(fieldError.getObjectName(), fieldError.getFieldPath()); vars.put("parentLabel", getMessage(parentCode, null)); } catch(Throwable e) { } try { String[] objectCode = messageCodeGenerator.generateObjectNameCodes(fieldError.getObjectName()); vars.put("objectLabel", getMessage(objectCode, null)); } catch(Throwable e) { } if(error instanceof CellFieldError) { final CellFieldError cellFieldError = (CellFieldError) error; vars.put("sheetName", cellFieldError.getSheetName()); vars.put("cellAddress", Utils.formatCellAddress(cellFieldError.getCellAddress())); } } else { // オブジェクトエラーのメッセージを処理する。 final String[] labelCode = messageCodeGenerator.generateObjectNameCodes(error.getObjectName()); if(error.getLabel() != null) { vars.put("label", error.getLabel()); } else { try { vars.put("label", getMessage(labelCode, null)); } catch(Throwable e) { } } try { String[] objectCode = messageCodeGenerator.generateObjectNameCodes(error.getObjectName()); vars.put("objectLabel", getMessage(objectCode, null)); } catch(Throwable e) { } if(error instanceof SheetObjectError) { final SheetObjectError sheetObjectError = (SheetObjectError) error; vars.put("sheetName", sheetObjectError.getSheetName()); } } final String message = getMessage(error.getCodes(), error.getDefaultMessage()); return messageInterporlator.interpolate(message, vars, false, messageResolver); } /** * 指定した引数の候補からメッセージを取得する。 * @param codes メッセージコードの候補 * @param defaultMessage メッセージコードが見つからない場合のメッセージ * @return */ public String getMessage(final String[] codes, final String defaultMessage) { for(String code : codes) { try { final String message = messageResolver.getMessage(code); if(message != null) { return message; } } catch(Throwable e) { continue; } } if(Utils.isNotEmpty(defaultMessage)) { return defaultMessage; } throw new RuntimeException(String.format("not found message code [%s].", Utils.join(codes, ","))); } public MessageResolver getMessageResolver() { return messageResolver; } public void setMessageResolver(MessageResolver messageResolver) { this.messageResolver = messageResolver; } public MessageInterpolator getMessageInterporlator() { return messageInterporlator; } public void setMessageInterporlator(MessageInterpolator messageInterporlator) { this.messageInterporlator = messageInterporlator; } public MessageCodeGenerator getMessageCodeGenerator() { return messageCodeGenerator; } public void setMessageCodeGenerator(MessageCodeGenerator messageCodeGenerator) { this.messageCodeGenerator = messageCodeGenerator; } }