たごもりすメモ

コードとかその他の話とか。

Dropwizard ValidatorがListに対して正常に動かない

Kotlinが悪いのかListはそもそもダメなのか既知の問題なのかなどはまだ確認してない。

追記: この問題っぽい。JVMのオプション追加でどうにかなるケースと、いややっぱダメみたいな話もあるのかな。トップレベルにListを使わないのが結局のところいちばんよさそう。うーん。

Dropwizard Validator*1を使って、YAMLから読んだデータのバリデーションをしようと思ったんだけど、なんかどうやってもエラーが報告されなくておっかしいなーと思ってたところ、どうもトップレベルがListだと正常に動かないっぽい。
以下のようなテストコードを書いて確認できる。

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
import io.dropwizard.jersey.validation.Validators
import javax.validation.Valid
import javax.validation.constraints.NotEmpty

val validator = Validators.newValidator()
val mapper = ObjectMapper(YAMLFactory()).registerKotlinModule()

data class TopLevel(
    @field:Valid val items: List<Item>
)

data class Item(
    @field:NotEmpty val data: String
)

class ValidationTest {
    @Test
    fun `validator does not report errors for top-level list`() {
        val yaml = """---
        |- data: ""
        |- data: ""
        |""".trimMargin()
        val list = mapper.readValue(yaml) as List<Item>
        assertNotEquals(emptySet(), validator.validate(list))
    }

    @Test
    fun `validator can report errors if top-level is not list`() {
        val yaml = """---
        |items:
        |  - data: ""
        |  - data: ""
        |""".trimMargin()
        val obj = mapper.readValue(yaml) as TopLevel
        assertNotEquals(emptySet(), validator.validate(obj))
    }
}

これでトップレベルがListのやつはエラーを報告せずfailし、トップレベルにdata classを置いてその子要素としてListを持たせたやつはバリデーションエラーを報告する。

f:id:tagomoris:20210209144401p:plain

条件を見付けるまでにだいぶ長いことハマってしまった。これ以上調べるかどうかはまだ決めてない。

*1:Hibernate由来の、Springとかでも使われてるやつ