MessageCodeGenerator.java
package com.github.mygreen.supercsv.validation;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import com.github.mygreen.supercsv.util.Utils;
/**
* メッセージのコードを生成するクラス。
* <p>Stringの「DefaultMessageCodeResolver」を参照。</p>
*
* @author T.TSUCHIE
*
*/
public class MessageCodeGenerator implements Serializable {
/** serialVersionUID */
private static final long serialVersionUID = 1L;
public static final String CODE_SEPARATOR = ".";
/** メッセージの接頭語 */
private String prefix = "";
/** 型変換エラー時のコード */
private String typeMismatchCode = "typeMismatch";
/**
* コードの候補を生成する。
* @param code
* @param objectName
* @return
*/
public String[] generateCodes(final String code, final String objectName) {
return generateCodes(code, objectName, null, null);
}
/**
* 型変換エラーコードの候補を生成する。
* @param objectName
* @param field
* @param fileType
* @return
*/
public String[] generateTypeMismatchCodes(final String objectName, final String field, final Class<?> fileType) {
return generateCodes(getTypeMismatchCode(), objectName, field, fileType);
}
/**
* オブジェクト名のキーの候補を生成する。
* @param objectName
* @return
*/
public String[] generateObjectNameCodes(final String objectName) {
Objects.requireNonNull(objectName, "objectName should not be null");
final List<String> codeList = new ArrayList<String>();
codeList.add(objectName);
// オブジェクト名の最後の値を取得する
final int dotIndex = objectName.lastIndexOf('.');
if(dotIndex > 0) {
final String subName = objectName.substring(dotIndex + 1);
codeList.add(subName);
}
return codeList.toArray(new String[codeList.size()]);
}
/**
* フィールド名のキーの候補を生成する。
* @param objectName
* @param field
* @return
*/
public String[] generateFieldNameCodes(final String objectName, final String field) {
final List<String> codeList = new ArrayList<String>();
codeList.addAll(Arrays.asList(generateCodes(null, objectName, field, null)));
// オブジェクト名の最後の値を取得する
final int dotIndex = objectName.lastIndexOf('.');
if(dotIndex > 0) {
final String subName = objectName.substring(dotIndex + 1);
for(String code : generateCodes(null, subName, field, null)) {
if(!codeList.contains(code)) {
codeList.add(code);
}
}
}
return codeList.toArray(new String[codeList.size()]);
}
/**
* フィールドの親のキーの候補を生成する。
* @param objectName オブジェクト名
* @param field フィールド
* @return
*/
public String[] generateParentNameCodes(final String objectName, final String field) {
if(Utils.isEmpty(field) || !field.contains(".")) {
return generateObjectNameCodes(objectName);
}
// フィールド名の前の値を取得する
final int dotIndex = field.lastIndexOf('.');
final String subName = field.substring(0, dotIndex);
return generateFieldNameCodes(objectName, subName);
}
/**
* キーの候補を生成する。
* <p>コンテキストのキーの形式として、次の優先順位に一致したものを返す。
*
* @param code 元となるメッセージのコード
* @param objectName オブジェクト名(クラスのフルパス)
* @param field フィールド名 (指定しない場合はnullを設定する)
* @param fieldType フィールドのクラスタイプ(指定しない場合はnullを設定する)
* @return
*/
public String[] generateCodes(final String code, final String objectName, final String field, final Class<?> fieldType) {
final String baseCode = getPrefix().isEmpty() ? code : getPrefix() + code;
final List<String> codeList = new ArrayList<>();
final List<String> fieldList = new ArrayList<>();
buildFieldList(field, fieldList);
addCodes(codeList, baseCode, objectName, fieldList);
if(Utils.isNotEmpty(field)) {
int dotIndex = field.lastIndexOf('.');
if(dotIndex > 0) {
buildFieldList(field.substring(dotIndex + 1), fieldList);
}
}
addCodes(codeList, code, null, fieldList);
if(fieldType != null) {
addCode(codeList, code, null, fieldType.getName());
// 列挙型の場合は、java.lang.Enumとしてクラスタイプを追加する。
if(Enum.class.isAssignableFrom(fieldType)) {
addCode(codeList, code, null, Enum.class.getName());
}
// 数値型の場合は、java.lang.Numberとしてクラスタイプを追加する。
if(Number.class.isAssignableFrom(fieldType)) {
addCode(codeList, code, null, Number.class.getName());
}
}
addCode(codeList, code, null, null);
return codeList.toArray(new String[codeList.size()]);
}
/**
* フィールドのパスを分解して、パスの候補を作成する。
* <p>インデックスを示す'[0]'を除いたりして組み立てる。
* @param field
* @param fieldList
*/
protected void buildFieldList(final String field, final List<String> fieldList) {
if(Utils.isEmpty(field)) {
return;
}
if(!fieldList.contains(field)) {
fieldList.add(field);
}
String plainField = String.valueOf(field);
int keyIndex = plainField.lastIndexOf('[');
while(keyIndex >= 0) {
int endKeyIndex = plainField.indexOf(']', keyIndex);
if(endKeyIndex >= 0) {
plainField = plainField.substring(0, keyIndex) + plainField.substring(endKeyIndex + 1);
if(!fieldList.contains(plainField)) {
fieldList.add(plainField);
}
keyIndex = plainField.lastIndexOf('[');
} else {
keyIndex = -1;
}
}
}
private void addCodes(final List<String> codeList, final String code, final String objectName, final List<String> fieldList) {
for(String field : fieldList) {
addCode(codeList, code, objectName, field);
}
}
private void addCode(final List<String> codeList, final String code, final String objectName, final String field) {
final String formattedCode = formatCode(code, objectName, field);
if(!codeList.contains(formattedCode)) {
codeList.add(formattedCode);
}
}
private String formatCode(final String... elements) {
// エラーコードを前に付ける場合
StringBuilder code = new StringBuilder();
for(String element : elements) {
if(Utils.isNotEmpty(element)) {
code.append(code.length() == 0 ? "" : CODE_SEPARATOR);
code.append(element);
}
}
return code.toString();
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getTypeMismatchCode() {
return typeMismatchCode;
}
public void setTypeMismatchCode(String typeMismatchCode) {
this.typeMismatchCode = typeMismatchCode;
}
}