🗣️

messages.ymlを運用していた時に詰まったこと

2024/05/28に公開

Spring bootで使うメッセージは通常messages.propertiesで管理すると思います。
ただ、やはりpropertiesファイルだと管理が辛いので、QiitaGithubのイシューを参考にymlを使うようにしました。

メッセージ取得ができない

ところが、あるAPIを開発中になぜかNoSuchMessageExceptionが発生するようになりました。
詳しく調査してみるとどうやら以下のように、CompletableFutureのラムダの中でメッセージリソースを取得しようとすると発生する、ということまで特定できました。

public MyClass {
  @Autowired
  private MessageSource messageSource;

  public String myMethod() {
    CompletableFuture(() -> {
      String message = messageSource.getMessage("hello.world", null, Locale.JAPAN);
    });
  }
}

原因

ブレークポイントを貼ってフレームワークの中まで追いかけてみましたが、どうやらリソースファイルをcotext:messages.ymlというURIで取得しようとしても、nullが返されてしまい、したがってプロパティ一覧も取得できないという状況になっていたようでした。

Intellij IDEA上では問題なく取得できるけど、jarにしてDockerコンテナ上では動かないことから、https://stackoverflow.com/questions/25869428/classpath-resource-not-found-when-running-as-jar と同事象のような気がしています。
ただし、上記QAではライブラリではなく自分でリソースファイルを取得するコードを書いている場合の解決策しか提示されておらず、根本的な解決には至りませんでした。

対策

CompletableFutureの前にmessageSourceによる取得を一度しておくと、以降キャッシュが効くのかエラーがでなくなりました。
ハッキーな対策ではありますが、いったん動作しているのでこれで様子を見てみます。

public MyClass {
  @Autowired
  private MessageSource messageSource;

  public String myMethod() {
    try {
      // 事前に読み込んでおく。
      messageSource.getMessage("", null, Locale.JAPAN);
    } catch(NoSuchMessageException e) {}
    
    CompletableFuture(() -> {
      String message = messageSource.getMessage("hello.world", null, Locale.JAPAN);
    });
  }
}

追記

職場のプロジェクトでは上記事象が発生したのですが、自宅でいちからプロジェクトを作成したらメッセージが取得できない事象が再現できませんでした・・・。
他に原因があるかいずれ調査してみます。

Discussion