The Kotlin Data Mapper (KDataMapper) is a Kotlin Symbol Processing plugin that can generate extension functions to map fields of one class to the primary constructor of another class.
Let's say we have the following entity:
data class ArticleEntity(
val id: Long,
val title: String,
val content: String,
val tags: List<String> = emptyList(),
)
Now we want to have DTOs for create and update entity:
data class ArticleCreateDto(
val title: String,
val content: String,
val tags: List<String> = emptyList(),
)
data class ArticleUpdateDto(
val id: Long,
val title: String,
val content: String,
val tags: List<String>,
)
To create mapping functions, you need to add the @KDataMapper
annotation and there are several options for this:
- Add annotation to the
ArticleEntity
and setfromClasses = [ArticleCreateDto::class, ArticleUpdateDto::class]
in the@KDataMapper
annotation
@DataMapper(
fromClasses = [ArticleCreateDto::class, ArticleUpdateDto::class],
)
data class ArticleEntity(
val id: Long,
val title: String,
val content: String,
val tags: List<String> = emptyList(),
)
- Or add annotations to DTOs and set
toClasses = [ArticleEntity::class]
in each@KDataMapper
annotation
@DataMapper(
toClasses = [ArticleEntity::class],
)
data class ArticleCreateDto(
val title: String,
val content: String,
val tags: List<String> = emptyList(),
)
@DataMapper(
toClasses = [ArticleEntity::class],
)
data class ArticleUpdateDto(
val id: Long,
val title: String,
val content: String,
val tags: List<String>,
)
When we build the project we'll have:
public fun ArticleCreateDto.toArticleEntity(id: Long) = ArticleEntity(
id = id,
title = title,
content = content,
tags = tags,
)
public fun ArticleUpdateDto.toArticleEntity() = ArticleEntity(
id = id,
title = title,
content = content,
tags = tags,
)
The id
parameter has been added to the ArticleCreateDto.toArticleEntity
function
because it's required in ArticleEntity
and has no default value.
Next, we want get a DTO with additional field that are not in ArticleEntity
:
@DataMapper(
fromClasses = [ArticleEntity::class],
)
data class ArticleWithCommentsDto(
val id: Long,
val title: String,
val bookmarkCount: Int,
val comments: List<String> = emptyList(),
)
After build we get:
public fun ArticleTitleDto.toArticleWithCommentsDto(bookmarkCount: Int, comments: List<String>) =
ArticleWithCommentsDto(
id = id,
title = title,
bookmarkCount = bookmarkCount,
comments = comments,
)
public fun ArticleTitleDto.toArticleWithCommentsDto(bookmarkCount: Int) = ArticleWithCommentsDto(
id = id,
title = title,
bookmarkCount = bookmarkCount,
)
Two functions are generated because the comments
field have a default value.
You can find a complete project example in the example
subdirectory.
Add KSP plugin to your module's build.gradle.kts
:
plugins {
id("com.google.devtools.ksp") version "1.9.22-1.0.16"
}
Add Maven Central
to the repositories blocks in your project's build.gradle.kts
:
repositories {
mavenCentral()
}
Add KDataMapper
dependencies:
dependencies {
implementation("io.github.darkxanter:kdatamapper-core:0.2.0")
ksp("io.github.darkxanter:kdatamapper-processor:0.2.0")
}
Copyright 2023 Sergey Shumov
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.