コードは Kotlin だけどよしなに読み替えてください。
前提
- Excel は便利なのでこれを使ってまとめて書きたい。どかっと記述して CSV で取り込みたい。
- とにかくフィールドが多い、可変かもしれない、増えるかもしれないし減るかもしれない。
やっていく
jackson-dataformat-csv を使えばできる。
https://github.com/FasterXML/jackson-dataformats-text/tree/master/csv
ドキュメントがかなりふわっとしていて難解だがやればできる。
import assertk.assert
import assertk.assertions.isEqualTo
import assertk.assertions.isNotNull
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.annotation.JsonUnwrapped
import com.fasterxml.jackson.dataformat.csv.CsvMapper
import com.fasterxml.jackson.dataformat.csv.CsvSchema
import org.junit.Test
class DeserializeTest {
enum class Country {
JP,
US
}
class Profile {
@JsonProperty("age")
val age: Int = 0
@JsonProperty("country")
val country: Country = Country.JP
}
class User {
@JsonProperty("_id")
val id: Int = 0
@JsonProperty("name")
val name: String = ""
@JsonUnwrapped(prefix = "profile.")
val profile: Profile? = null
}
@Test
fun deserialize() {
val mapper = CsvMapper()
val schema = CsvSchema.emptySchema().withHeader()
val reader = mapper.readerFor(User::class.java).with(schema)
val users = reader.readValues<User>("""
name,_id,profile.age,profile.country
foo,3,17,JP
bar,2,21,US
""".trim()).readAll()
assert(users[0].id).isEqualTo(3)
assert(users[0].name).isEqualTo("foo")
assert(users[0].profile).isNotNull {
assert(it.actual.age).isEqualTo(17)
assert(it.actual.country).isEqualTo(Country.JP)
}
assert(users[1].id).isEqualTo(2)
assert(users[1].name).isEqualTo("bar")
assert(users[1].profile).isNotNull {
assert(it.actual.age).isEqualTo(21)
assert(it.actual.country).isEqualTo(Country.US)
}
}
}
ポイントは CsvSchema に型情報を与えないこと。
ここで型情報を渡すととにかくカラムの順序ベースでしかデシリアライズしてくれなくてはまる。
@JsonUnwrapped
が地味にすごい。便利。
JavaBeans を要求されるので Kotlin で書いているなら non-null については諦めてください。悲しいですね。