Konvert
Konvert генерирует реализации мапперов Kotlin с помощью KSP. Kora делает сгенерированные реализации обычными компонентами контейнера зависимостей. Для Java смотрите MapStruct.
Konvert¶
Konvert генерирует мапперы для Kotlin средствами KSP.
Поскольку это KSP-обработчик, он работает в той же компиляции, что и Kotlin-обработчики Kora, поэтому Konvert подключается просто как ещё одна зависимость ksp(...) и не требует дополнительной настройки сборки.
Расширение для Konvert поставляется внутри io.koraframework:symbol-processors. Оно регистрируется через ServiceLoader и активируется только тогда, когда тип аннотации io.mcarle.konvert.api.Konverter доступен в classpath: в проекте без Konvert оно не делает ничего.
Подключение¶
Зависимость в build.gradle.kts:
ksp("io.mcarle:konvert:4.5.1") //(1)!
ksp("io.koraframework:symbol-processors:2.0.0.RC2") //(2)!
implementation("io.mcarle:konvert-api:4.5.1") //(3)!
KSP-обработчикKonvert— именно он генерирует реализации мапперов (обязательный, без значения по умолчанию).KSP-обработчики Kora, в составе которых идёт расширение дляKonvert(обязательный, без значения по умолчанию).- Аннотации
Konvert, в том числе@Konverter(обязательный, без значения по умолчанию).
Как и в случае с MapStruct в Java, версии Konvert вы выбираете сами: kora-bom ограничивает только артефакты io.koraframework:*.
Использование¶
Пометьте интерфейс аннотацией @Konverter и объявите преобразования его методами:
data class Car(val make: String, val seatCount: Int)
data class CarDto(val make: String, val seatCount: Int)
@Konverter
interface CarMapper {
fun carToCarDto(car: Car): CarDto
}
Konvert генерирует в том же пакете объект верхнего уровня object CarMapperImpl : CarMapper, а расширение Kora публикует этот объект в графе под типом CarMapper.
Маппер не нужно помечать аннотацией @Component и не нужно подключать никакой модуль.
Переименование полей, вычисляемые значения и любые другие правила по отдельным свойствам задаются собственными аннотациями Konvert — см. документацию Konvert.
Внедрённый маппер — обычный компонент:
@Component
class CarService(private val carMapper: CarMapper) {
fun convert(car: Car): CarDto {
return carMapper.carToCarDto(car)
}
}
Тег¶
@Konverter может быть уточнён тегом @Tag: объявите один и тот же тег на интерфейсе маппера и в точке внедрения — и маппер будет предоставлен именно там.
@Tag(MyTag::class)
@Konverter
interface CarMapper {
fun carToCarDto(car: Car): CarDto
}
@Component
class CarService(@Tag(MyTag::class) private val carMapper: CarMapper)
Ограничения¶
@Konverterраспознаётся только на интерфейсе. Абстрактный класс с аннотацией@Konverterрасширением не предоставляется.- Сгенерированная реализация — это Kotlin-
object, у него нет конструктора, и он не может получить ничего из графа. Маппер, которому нужен вспомогательный компонент, приходится писать как обычный @Component, делегирующий сгенерированному объектуCarMapperImpl. - Реализация ищется как
<SimpleName>Implв пакете самого маппера. Для@Konverter, вложенного в другой тип,Konvertвсё равно генерирует объект верхнего уровня и отбрасывает имя внешнего типа — поэтому поиск отбрасывает его тоже.
Ошибки¶
Generated Konvert implementation was not found(далее следуетexpected type: <package>.<Name>Impl) — графу потребовался тип с@Konverter, но сгенерированного объекта нет. ЛибоKSP-обработчикKonvertне объявлен в этом модуле, либоKonvertзавершился с ошибкой раньше в той же компиляции и вывел собственные сообщения выше этого. Исправьте первую сообщённую ошибку и пересоберите проект.