概要
記事名通り。
テストクラスが作りやすくなるかな~みたいな軽いノリで、具象クラスであるCsvMapperをBean登録していたら大変な目にあいました。本記事は現場のコードで起きた問題を私用PCの環境で簡単に再現したものです。
環境 (というか主なpom)
spring-boot-starter-parent 2.7.4
-- spring-boot-starter
-- spring-boot-starter-jdbc
-- spring-boot-starter-thymeleaf
-- spring-boot-starter-web
-- spring-boot-starter-actuator
現象
SpringBootのヘルスチェック
Springbootさんはmavenやgradleで依存関係にspring-boot-starter-actuatorをぶち込むだけで、勝手にヘルスチェック機能を実装してくれます。
$ curl -f http://localhost:8080/actuator/health
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 15 0 15 0 0 2249 0 --:--:-- --:--:-- --:--:-- 3000{"status":"UP"}
デフォルトは/acutuator/health がパスになっておりますが、springbootのプロパティでこのへんは色々いじれるっぽいです。 また、同じくプロパティを使ってDBのヘルスチェックなんかも設定できます。
CsvMapperをBean登録して起こったこと。
ここで、本題です.とある現場で、DBから取得した情報でCSVファイルを出力する機能を実装することになりました。下はイメージ図です。
@Controller
public class HelloWorldController {
@RequestMapping("/")
public String hello(@ModelAttribute SimpleForm simpleForm,Model model) {
CsvMapper csvMapper = new CsvMapper();
// DB接続するなりして、CsvMpperでデータアウトプットしたりする...
return "main";
}
}
ここで、CsvMapperをDI登録してしまえば、Mock化できるのでこのクラスの単体テストが楽になる!!と考えました。
つまり、
@Configuration
public class SimpleGamenConfig {
@Bean
public CsvMapper csvMapper() {
return new CsvMapper();
}
}
@Controller
public class HelloWorldController {
@Autowired
CsvMapper csvMapper;
@RequestMapping("/")
public String hello(@ModelAttribute SimpleForm simpleForm,Model model) {
// DB接続するなりして、CsvMpperでデータアウトプットしたりする...
return "main";
}
}
こうです。
結果、SpringbootApplicationも起動しますし、画面も問題なく動きました。
しかし、ヘルスチェックが落ちるようになります。
$ curl -f http://localhost:8080/actuator/health
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
curl: (22) The requested URL returned error: 500
ログを見てみると、どうやらヘルスチェック時に返却されるJson形式のステータスデータがうまく出力できていないようです。。
2022-10-26 22:40:34.793 WARN 21648 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Unrecognized column 'status': known columns: []; nested exception is com.fasterxml.jackson.dataformat.csv.CsvWriteException: Unrecognized column 'status': known columns: [] (through reference chain: org.springframework.boot.actuate.health.SystemHealth["status"]->org.springframework.boot.actuate.health.Status["status"])]
2022-10-26 22:40:34.795 WARN 21648 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Unrecognized column 'timestamp': known columns: []; nested exception is com.fasterxml.jackson.dataformat.csv.CsvWriteException: Unrecognized column 'timestamp': known columns: [] (through reference chain: java.util.LinkedHashMap["timestamp"])]
Springbootのヘルスチェック内でObjectMapperのインスタンスを使っている?ようで、それをCsvMapperに上書いてしまったせいでこのようなエラーが起こるようです。
詳しくはまた今度調べてみます。
以上、初記事でした。