1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【SpringBoot】Validationでプレースホルダが認識されなくてハマった話

Posted at

はじめに

表題の件についてまとめます。APIの仕様をちゃんと確認しよう、というお話です。

SpringBootのValidationで「{0}」がそのまま出力される

バリデーションエラー時にプレースホルダを利用してエラーメッセージを出力しようとしました。
「{0}」を使えば、フィールド名が出力されることを期待して、jakarta.validation.constraints.NotNull.message=「{0}」は必須入力ですのようにValidationMessages.properiesへ記述したところ、表示された文字は「{0}」は必須入力ですとなりました。
これでハマること2時間。。。

原因

エラーメッセージを出力しようとしていたコードは次のとおりです。

    
    @PostMapping
    public ResponseEntity<?> postSomething(@Validated @RequestBody SomethingForm somethingForm, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            StringBuilder errorMessage = new StringBuilder();
            for (ObjectError error : bindingResult.getAllErrors()) {
                errorMessage.append(error.getDefaultMessage()).append("; ");
            }
            return ResponseEntity.badRequest().body(errorMessage.toString());
        }
        
        stocks.add(stocksAddForm);

        return ResponseEntity.ok("Stock info added successfully!");
    }

ValidationMessages.properiesの記述の仕方や@Configを追加したりと色々試してもうまくいかず、途方に暮れていたところ、ついにたどり着いた部分がこれです。
error.getDefaultMessage()
そもそもエラーメッセージの出力がどのようにして行われているのか、はたと気づいて調べた結果、通常、BindingResult.getAllErrors() で取得したエラーメッセージは、プレースホルダーが解決されていない状態で返されることが分かりました。
うまくいかないのも当たり前です。。。

解決

コードを次のように修正しました。

    
+    private final MessageSource messageSource;
+    
+    public StocksController(MessageSource messageSource) {
+        this.messageSource = messageSource;
+    }

    @PostMapping
-    public ResponseEntity<?> postStocks(@Validated @RequestBody StocksAddForm stocksAddForm, BindingResult bindingResult) {
+    public ResponseEntity<?> postStocks(@Validated @RequestBody StocksAddForm stocksAddForm, BindingResult bindingResult, Locale locale) {
        if (bindingResult.hasErrors()) {
+            StringBuilder errorMessage = new StringBuilder();
            for (ObjectError error : bindingResult.getAllErrors()) {
-               errorMessage.append(error.getDefaultMessage()).append("; ");
+               String message = messageSource.getMessage(error, locale);
+               errorMessage.append(message).append("; ");
            }
            return ResponseEntity.badRequest().body(errorMessage.toString());
        }
        
        stocks.add(stocksAddForm);

        return ResponseEntity.ok("Stock info added successfully!");
    }

MessageSourceのgetMessage()メソッドを使うことで、プレースホルダが正しく解釈されて出力されました。

結論

適当に引っ張ってきたコードをそのまま使わず、その意味をきちんと丁寧に理解しなければならないと痛感しました。。。
よく分からないところに原因は潜んでいるのかも。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?