Kotlinでdataクラスのマッピングするためのメモ。
Beanマッピングでおなじみの(?)MapStructを使用する。
Kotlin: 1.3.61 MapStruct: 1.3.1.Final
MapStruct
公式サイトにKotlinのサンプルがある。
build.gradleに以下を追加する。
dependencies { // omit... implementation 'org.mapstruct:mapstruct:1.3.1.Final' kapt 'org.mapstruct:mapstruct-processor:1.3.1.Final' }
dataクラスを用意する。
各プロパティは mutable かつ nullable で、引数なしのセカンダリコンストラクタを用意する必要がある。
data class Person( var firstName: String?, var lastName: String? ) { constructor() : this(null, null) } data class PersonDto( var firstName: String?, var lastName: String? ) { constructor() : this(null, null) }
Mapperクラスを用意する。
@Mapper interface PersonMapper { fun map(dto: PersonDto): Person fun map(person: Person): PersonDto }
以上で準備は完了。動かしてみるとマッピングしてくれる。
fun main() { val mapper = Mappers.getMapper(PersonMapper::class.java) val dto = PersonDto("家康", "徳川") val person = mapper.map(dto) println(person) // -> Person(firstName=家康, lastName=徳川) val personDto = mapper.map(person) println(personDto) // -> PersonDto(firstName=家康, lastName=徳川) }
mapstruct-kotlin
マッピングできたのは良いが、MapStructを使うために mutable やnullable にしたり、セカンダリコンストラクタの用意が必要だったり使うには少しためらわれる。 この問題を解決するのが mapstruct-kotlin 。
build.gradleに以下を追加する。
dependencies { // omit... api 'com.github.pozo:mapstruct-kotlin:1.3.1.1' kapt 'com.github.pozo:mapstruct-kotlin-processor:1.3.1.1' }
dataクラスに @KotlinBuilder
を付与する。
@KotlinBuilder data class Person( val firstName: String, val lastName: String ) @KotlinBuilder data class PersonDto( val firstName: String, val lastName: String )
MapperクラスはそのままでOK。
@Mapper interface PersonMapper { fun map(dto: PersonDto): Person fun map(person: Person): PersonDto }
以上で準備は完了。期待通りマッピングしてくれる。
fun main() { val mapper = Mappers.getMapper(PersonMapper::class.java) val dto = PersonDto("家康", "徳川") val person = mapper.map(dto) println(person) // -> Person(firstName=家康, lastName=徳川) val personDto = mapper.map(person) println(personDto) // -> PersonDto(firstName=家康, lastName=徳川) }