package sample; import java.io.Serializable; import java.util.*; import lombok.Value; /** * 審査例外を表現します。 * <p>ValidationExceptionは入力例外や状態遷移例外等の復旧可能な審査例外です。 * その性質上ログ等での出力はWARNレベル(ERRORでなく)で行われます。 * <p>審査例外はグローバル/フィールドスコープで複数保有する事が可能です。複数件の例外を取り扱う際は * Warnsを利用して初期化してください。 */ public class ValidationException extends RuntimeException { private static final long serialVersionUID = 1L; private final Warns warns; /** フィールドに従属しないグローバルな審査例外を通知するケースで利用してください。 */ public ValidationException(String message) { super(message); warns = Warns.init(message); } /** フィールドに従属する審査例外を通知するケースで利用してください。 */ public ValidationException(String field, String message) { super(message); warns = Warns.init(field, message); } /** フィールドに従属する審査例外を通知するケースで利用してください。 */ public ValidationException(String field, String message, String[] messageArgs) { super(message); warns = Warns.init(field, message, messageArgs); } /** 複数件の審査例外を通知するケースで利用してください。 */ public ValidationException(final Warns warns) { super(warns.head().map((v) -> v.getMessage()).orElse(ErrorKeys.Exception)); this.warns = warns; } /** 発生した審査例外一覧を返します。*/ public List<Warn> list() { return warns.list(); } @Override public String getMessage() { return warns.head().map((v) -> v.getMessage()).orElse(ErrorKeys.Exception); } /** 審査例外情報です。 */ public static class Warns implements Serializable { private static final long serialVersionUID = 1L; private List<Warn> list = new ArrayList<>(); private Warns() { } public Warns add(String message) { list.add(new Warn(null, message, null)); return this; } public Warns add(String field, String message) { list.add(new Warn(field, message, null)); return this; } public Warns add(String field, String message, String[] messageArgs) { list.add(new Warn(field, message, messageArgs)); return this; } public Optional<Warn> head() { return list.isEmpty() ? Optional.empty() : Optional.of(list.get(0)); } public List<Warn> list() { return list; } public boolean nonEmpty() { return !list.isEmpty(); } public static Warns init() { return new Warns(); } public static Warns init(String message) { return init().add(message); } public static Warns init(String field, String message) { return init().add(field, message); } public static Warns init(String field, String message, String[] messageArgs) { return init().add(field, message, messageArgs); } } /** フィールドスコープの審査例外トークンを表現します。 */ @Value public static class Warn implements Serializable { private static final long serialVersionUID = 1L; /** 審査例外フィールドキー */ private String field; /** 審査例外メッセージ */ private String message; /** 審査例外メッセージ引数 */ private String[] messageArgs; /** フィールドに従属しないグローバル例外時はtrue */ public boolean global() { return field == null; } } /** 審査例外で用いるメッセージキー定数 */ public static interface ErrorKeys { /** サーバー側で問題が発生した可能性があります */ String Exception = "error.Exception"; /** 情報が見つかりませんでした */ String EntityNotFound = "error.EntityNotFoundException"; /** ログイン状態が有効ではありません */ String Authentication = "error.Authentication"; /** 対象機能の利用が認められていません */ String AccessDenied = "error.AccessDeniedException"; /** ログインに失敗しました */ String Login = "error.login"; /** 既に登録されているIDです */ String DuplicateId = "error.duplicateId"; /** 既に処理済の情報です */ String ActionUnprocessing = "error.ActionStatusType.unprocessing"; } }