The Kotlin Object Multiplatform Mapper provides you a possibility to generate (via KSP) extension function to map one object to another.
- Supports KSP Multiplatform
- Maps as constructor parameters as well as public properties with setter
- Supports properties types cast
- Supports Java objects get* functions
- Supports multi source classes with separated configurations
- Has next properties annotations:
- Specify mapping from property with different name
- Specify a converter to map data from source unusual way
- Specify a resolver to map default values into properties
- Specify null substitute to map nullable properties into not-nullable
- Support extension via plugins
- Iterable Plugin:
- Support collections mapping with different types of elements
plugins {
id("com.google.devtools.ksp") version "2.0.20-1.0.25"
}
val kommVersion = "0.20.2"
depensencies {
implementation("com.ucasoft.komm:komm-annotations:$kommVersion")
ksp("com.ucasoft.komm:komm-processor:$kommVersion")
}
plugins {
id("com.google.devtools.ksp") version "2.0.20-1.0.25"
}
val kommVersion = "0.20.2"
kotlin {
jvm {
withJava()
}
js(IR) {
nodejs()
}
// Add other platforms
sourceSets {
val commonMain by getting {
dependencies {
implementation("com.ucasoft.komm:komm-annotations:$kommVersion")
}
}
val jvmMain by getting
val jsMain by getting
// Init other sourceSets
}
}
dependencies {
add("kspJvm", "com.ucasoft.komm:komm-processor:$kommVersion")
add("kspJs", "com.ucasoft.komm:komm-processor:$kommVersion")
// Add other platforms like `kspAndroidNativeX64`, `kspLinuxX64`, `kspMingwX64` etc.
}
class SourceObject {
val id = 150
val intToString = 300
val stringToInt = "250"
}
@KOMMMap(from = [SourceObject::class])
data class DestinationObject(
val id: Int,
val stringToInt: Int
) {
var intToString: String = ""
}
or
@KOMMMap(to = [DestinationObject::class])
class SourceObject {
val id = 150
val intToString = 300
val stringToInt = "250"
}
data class DestinationObject(
val id: Int,
val stringToInt: Int
) {
var intToString: String = ""
}
fun SourceObject.toDestinationObject(): DestinationObject = DestinationObject(
id = id,
stringToInt = stringToInt.toInt()
).also {
it.intToString = intToString.toString()
}
@KOMMMap(
from = [SourceObject::class],
config = MapConfiguration(
tryAutoCast = false
)
)
data class DestinationObject(
val id: Int,
val stringToInt: Int
) {
var intToString: String = ""
}
e: [ksp] com.ucasoft.komm.processor.exceptions.KOMMCastException: AutoCast is turned off! You have to use @MapConvert annotation to cast (stringToInt: Int) from (stringToInt: String)
@KOMMMap(
from = [SourceObject::class],
config = MapConfiguration(
convertFunctionName = "convertToDestination"
)
)
data class DestinationObject(
val id: Int,
val stringToInt: Int
) {
var intToString: String = ""
}
fun SourceObject.convertToDestination(): DestinationObject = DestinationObject(
id = id,
stringToInt = stringToInt.toInt()
).also {
it.intToString = intToString.toString()
}
class SourceObject {
//...
val userName = "user"
}
@KOMMMap(from = [SourceObject::class])
data class DestinationObject(
//...
@MapName("userName")
val name: String
) {
var intToString: String = ""
}
or
@KOMMMap(to = [DestinationObject::class])
class SourceObject {
//...
@MapName("name")
val userName = "user"
}
data class DestinationObject(
//...
val name: String
) {
var intToString: String = ""
}
fun SourceObject.toDestinationObject(): DestinationObject = DestinationObject(
//...
name = userName
).also {
it.intToString = intToString.toString()
}
class CostConverter(source: SourceObject) : KOMMConverter<SourceObject, Double, String>(source) {
override fun convert(sourceMember: Double) = "$sourceMember ${source.currency}"
}
class SourceObject {
//...
val cost = 499.99
}
@KOMMMap(from = [SourceObject::class])
data class DestinationObject(
//...
@MapConvert<SourceObject, CostConverter>(CostConverter::class)
val cost: String
) {
//...
@MapConvert<SourceObject, CostConverter>(CostConverter::class, "cost")
var otherCost: String = ""
}
fun SourceObject.toDestinationObject(): DestinationObject = DestinationObject(
//...
cost = CostConverter(this).convert(cost)
).also {
//...
it.otherCost = CostConverter(this).convert(cost)
}
class DateResolver(destination: DestinationObject?) : KOMMResolver<DestinationObject, Date>(destination) {
override fun resolve(): Date = Date.from(Instant.now())
}
@KOMMMap(from = [SourceObject::class])
data class DestinationObject(
//...
@MapDefault<DateResolver>(DateResolver::class)
val activeDate: Date
) {
//...
@MapDefault<DateResolver>(DateResolver::class)
var otherDate: Date = Date.from(Instant.now())
}
fun SourceObject.toDestinationObject(): DestinationObject = DestinationObject(
//...
activeDate = DateResolver(null).resolve()
).also {
//...
it.otherDate = DateResolver(it).resolve()
}
@KOMMMap(
from = [SourceObject::class],
config = MapConfiguration(
allowNotNullAssertion = true
)
)
data class DestinationObject(
val id: Int
)
data class SourceObject(
val id: Int?
)
fun SourceObject.toDestinationObject(): DestinationObject = DestinationObject(
id = id!!
)
e: [ksp] com.ucasoft.komm.processor.exceptions.KOMMCastException: Auto Not-Null Assertion is not allowed! You have to use @NullSubstitute annotation for id property.
class IntResolver(destination: DestinationObject?): KOMMResolver<DestinationObject, Int>(destination) {
override fun resolve() = 1
}
@KOMMMap(
from = [SourceObject::class]
)
data class DestinationObject(
@NullSubatitute(MapDefault(IntResolver::class))
val id: Int
) {
@NullSubatitute(MapDefault(IntResolver::class), "id")
var otherId: Int = 0
}
fun SourceObject.toDestinationObject(): DestinationObject = DestinationObject(
id = id ?: IntResolver(null).resolve()
).also {
it.otherId = id ?: IntResolver(it).resolve()
}
@KOMMMap(
to = [DestinationObject::class]
)
data class SourceObject(
@NullSubatitute(MapDefault(IntResolver::class))
val id: Int?
)
fun SourceObject.toDestinationObject(): DestinationObject = DestinationObject(
id = id ?: IntResolver(null).resolve()
)
@KOMMMap(
from = [FirstSourceObject::class, SecondSourceObject::class]
)
data class DestinationObject(
@NullSubatitute(MapDefault(IntResolver::class), [FirstSourceObject::class])
@MapName("userId", [SecondSourceObject::class])
val id: Int
) {
@NullSubatitute(MapDefault(IntResolver::class), "id", [FirstSourceObject::class])
var otherId: Int = 0
}
data class FirstSourceObject(
val id: Int?
)
data class SecondSourceObject(
val userId: Int
)
in case, different sources should be configured different:
@KOMMMap(
from = [FirstSourceObject::class],
config = MapConfiguration(
allowNotNullAssertion = true
)
)
@KOMMMap(
from = [SecondSourceObject::class]
)
data class DestinationObject(
@NullSubatitute(MapDefault(IntResolver::class), [FirstSourceObject::class])
@MapName("userId", [SecondSourceObject::class])
val id: Int
) {
@NullSubatitute(MapDefault(IntResolver::class), "id", [FirstSourceObject::class])
var otherId: Int = 0
}
fun FirstSourceObject.toDestinationObject(): DestinationObject = DestinationObject(
id = id ?: IntResolver(null).resolve()
).also {
it.otherId = id ?: IntResolver(it).resolve()
}
fun SecondSourceObject.toDestinationObject(): DestinationObject = DestinationObject(
id = userId
)
plugins {
id("com.google.devtools.ksp") version "2.0.20-1.0.25"
}
val kommVersion = "0.20.2"
depensencies {
implementation("com.ucasoft.komm:komm-annotations:$kommVersion")
ksp("com.ucasoft.komm:komm-processor:$kommVersion")
ksp("com.ucasoft.komm:komm-plugins-iterable:$kommVersion")
}
plugins {
id("com.google.devtools.ksp") version "2.0.20-1.0.25"
}
val kommVersion = "0.20.2"
//...
dependencies {
add("kspJvm", "com.ucasoft.komm:komm-plugins-iterable:$kommVersion")
add("kspJvm", "com.ucasoft.komm:komm-processor:$kommVersion")
add("kspJs", "com.ucasoft.komm:komm-plugins-iterable:$kommVersion")
add("kspJs", "com.ucasoft.komm:komm-processor:$kommVersion")
// Add other platforms like `kspAndroidNativeX64`, `kspLinuxX64`, `kspMingwX64` etc.
}
class SourceObject {
val intList: List<Int>? = listOf(1, 2, 3)
}
@KOMMMap(from = [SourceObject::class], config = MapConfiguration(allowNotNullAssertion = true))
data class DestinationObject(
@MapName("intList")
val stringList: MutableList<String>
)
public fun SourceObject.toDestinationObject(): DestinationObject = DestinationObject(
stringList = intList!!.map { it.toString() }.toMutableList()
)
class SourceObject {
val intList: List<Int>? = listOf(1, 2, 3)
}
@KOMMMap(from = [SourceObject::class])
data class DestinationObject(
@NullSubstitute(MapDefault(StringListResolver::class), "intList")
val stringList: MutableList<String>
)
public fun SourceObject.toDestinationObject(): DestinationObject = DestinationObject(
stringList = intList?.map { it.toString() }?.toMutableList() ?: StringListResolver(null).resolve()
)
plugins {
id("com.google.devtools.ksp") version "2.0.20-1.0.25"
}
val kommVersion = "0.20.2"
depensencies {
implementation("com.ucasoft.komm:komm-annotations:$kommVersion")
ksp("com.ucasoft.komm:komm-processor:$kommVersion")
ksp("com.ucasoft.komm:komm-plugins-exposed:$kommVersion")
}
object SourceObject: Table() {
val id = integer("id").autoIncrement()
val name = varchar("name", 255)
val age = integer("age")
override val primaryKey = PrimaryKey(id)
}
@KOMMMap(from = [SourceObject::class])
data class DestinationObject(
val id: Int,
val name: String,
val age: Int
)
public fun ResultRow.toDestinationObject(): DestinationObject = DestinationObject(
id = this[SourceObject.id],
name = this[SourceObject.name],
age = this[SourceObject.age]
)