https://github.com/scogun/komm
Kotlin Object Multiplatform Mapper
https://github.com/scogun/komm
kotlin kotlin-multiplatform mapper
Last synced: 22 days ago
JSON representation
Kotlin Object Multiplatform Mapper
- Host: GitHub
- URL: https://github.com/scogun/komm
- Owner: Scogun
- License: apache-2.0
- Created: 2024-01-06T13:05:06.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-04-14T08:15:52.000Z (about 1 year ago)
- Last Synced: 2024-04-14T09:51:28.900Z (about 1 year ago)
- Topics: kotlin, kotlin-multiplatform, mapper
- Language: Kotlin
- Homepage:
- Size: 223 KB
- Stars: 8
- Watchers: 2
- Forks: 0
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Kotlin Object Multiplatform Mapper (KOMM)
The **Kotlin Object Multiplatform Mapper** provides you a possibility to generate (via [KSP](https://github.com/google/ksp)) extension function to map one object to another.
[](https://sonarcloud.io/summary/new_code?id=Scogun_komm)
[](https://sonarcloud.io/summary/new_code?id=Scogun_komm)
[](https://sonarcloud.io/summary/new_code?id=Scogun_komm)


[](https://search.maven.org/artifact/com.ucasoft.komm/komm-annotations)
[](https://search.maven.org/artifact/com.ucasoft.komm/komm-processor)
[](https://search.maven.org/artifact/com.ucasoft.komm/komm-plugins-iterable)
---
* [Features](#features)
* [Supported targets](#supported-targets)
* [Default plugins](#default-plugins)
* [Usage](#usage)
* [Add](#add-with-gradle)
* [JVM project](#jvm-project)
* [Multiplatform project](#multiplatform-project)
* [Simple mapping](#simple-mapping)
* [Configuration](#mapping-configuration)
* [Disable AutoCast](#disable-autocast)
* [Change Convert Function Name](#change-convert-function-name)
* [@MapName](#mapname-annotation)
* [@MapConverter](#use-converter)
* [@MapDefault](#use-resolver)
* [@NullSubstitute](#use-nullsubstitute)
* [Allow Not-Null Assertion](#mapping-configuration-1)
* [Multi Sources](#multi-sources-support)
* [Plugins](#plugins)
* [Iterable Plugin - Collections Mapping](#iterable-plugin---collections-mapping)
* [Add](#add-with-gradle-1)
* [JVM project](#jvm-project-1)
* [Multiplatform project](#multiplatform-project-1)
* [Allow NotNullAssertion](#allow-notnullassertion)
* [NullSubstitute](#nullsubstitute)
* [Exposed Plugin - ResultRow Mapping](#exposed-plugin---resultrow-mapping)
* [Add](#add-with-gradle-2)
* [Usage](#usage-1)
---## Features
* 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## Supported targets
* JVM
* JavaScript
* Linux
* Windows (mingwX64)
* macOS
* iOS## Default plugins
* Iterable Plugin:
* Support collections mapping with different types of elements
* Exposed Plugin:
* Support mapping from Exposed Table Object (ResultRow)## Usage
### Add with Gradle#### JVM Project
```kotlin
plugins {
id("com.google.devtools.ksp") version "2.1.0-1.0.28"
}val kommVersion = "0.22.8"
depensencies {
implementation("com.ucasoft.komm:komm-annotations:$kommVersion")
ksp("com.ucasoft.komm:komm-processor:$kommVersion")
}
```
#### Multiplatform Project
```kotlin
plugins {
id("com.google.devtools.ksp") version "2.1.0-1.0.28"
}val kommVersion = "0.22.8"
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.
}
```### Simple Mapping
#### Classes declaration
```kotlin
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
```kotlin
@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 = ""
}
```
#### Generated extension function
```kotlin
fun SourceObject.toDestinationObject(): DestinationObject = DestinationObject(
id = id,
stringToInt = stringToInt.toInt()
).also {
it.intToString = intToString.toString()
}
```### Mapping Configuration
#### Disable AutoCast
###### Classes declaration
```kotlin
@KOMMMap(
from = [SourceObject::class],
config = MapConfiguration(
tryAutoCast = false
)
)
data class DestinationObject(
val id: Int,
val stringToInt: Int
) {
var intToString: String = ""
}
```
###### Generation result
```console
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)
```
#### Change Convert Function Name
###### Classes declaration
```kotlin
@KOMMMap(
from = [SourceObject::class],
config = MapConfiguration(
convertFunctionName = "convertToDestination"
)
)
data class DestinationObject(
val id: Int,
val stringToInt: Int
) {
var intToString: String = ""
}
```
###### Generated extension function
```kotlin
fun SourceObject.convertToDestination(): DestinationObject = DestinationObject(
id = id,
stringToInt = stringToInt.toInt()
).also {
it.intToString = intToString.toString()
}
```### @MapName annotation
#### Classes declaration
```kotlin
class SourceObject {
//...
val userName = "user"
}@KOMMMap(from = [SourceObject::class])
data class DestinationObject(
//...
@MapName("userName")
val name: String
) {
var intToString: String = ""
}
```
or
```kotlin
@KOMMMap(to = [DestinationObject::class])
class SourceObject {
//...
@MapName("name")
val userName = "user"
}data class DestinationObject(
//...
val name: String
) {
var intToString: String = ""
}
```
#### Generated extension function
```kotlin
fun SourceObject.toDestinationObject(): DestinationObject = DestinationObject(
//...
name = userName
).also {
it.intToString = intToString.toString()
}
```### Use Converter
#### Converter declaration
```kotlin
class CostConverter(source: SourceObject) : KOMMConverter(source) {override fun convert(sourceMember: Double) = "$sourceMember ${source.currency}"
}
```
#### Classes declaration
```kotlin
class SourceObject {
//...
val cost = 499.99
}@KOMMMap(from = [SourceObject::class])
data class DestinationObject(
//...
@MapConvert(CostConverter::class)
val cost: String
) {
//...
@MapConvert(CostConverter::class, "cost")
var otherCost: String = ""
}
```
#### Generated extension function
```kotlin
fun SourceObject.toDestinationObject(): DestinationObject = DestinationObject(
//...
cost = CostConverter(this).convert(cost)
).also {
//...
it.otherCost = CostConverter(this).convert(cost)
}
```
### Use Resolver
#### Resolver declaration
```kotlin
class DateResolver(destination: DestinationObject?) : KOMMResolver(destination) {
override fun resolve(): Date = Date.from(Instant.now())
}
```
#### Classes declaration
```kotlin
@KOMMMap(from = [SourceObject::class])
data class DestinationObject(
//...
@MapDefault(DateResolver::class)
val activeDate: Date
) {
//...
@MapDefault(DateResolver::class)
var otherDate: Date = Date.from(Instant.now())
}
```
#### Generated extension function
```kotlin
fun SourceObject.toDestinationObject(): DestinationObject = DestinationObject(
//...
activeDate = DateResolver(null).resolve()
).also {
//...
it.otherDate = DateResolver(it).resolve()
}
```
### Use NullSubstitute
#### Mapping configuration
###### Classes declaration
```kotlin
@KOMMMap(
from = [SourceObject::class],
config = MapConfiguration(
allowNotNullAssertion = true
)
)
data class DestinationObject(
val id: Int
)
data class SourceObject(
val id: Int?
)
```
###### Generated extension function
```kotlin
fun SourceObject.toDestinationObject(): DestinationObject = DestinationObject(
id = id!!
)
```
###### Otherwise
```console
e: [ksp] com.ucasoft.komm.processor.exceptions.KOMMCastException: Auto Not-Null Assertion is not allowed! You have to use @NullSubstitute annotation for id property.
```
#### Resolver declaration
```kotlin
class IntResolver(destination: DestinationObject?): KOMMResolver(destination) {override fun resolve() = 1
}
```
#### Classes declaration Map From
```kotlin
@KOMMMap(
from = [SourceObject::class]
)
data class DestinationObject(
@NullSubstitute(MapDefault(IntResolver::class))
val id: Int
) {
@NullSubstitute(MapDefault(IntResolver::class), "id")
var otherId: Int = 0
}
```
#### Generated extension function for Map From
```kotlin
fun SourceObject.toDestinationObject(): DestinationObject = DestinationObject(
id = id ?: IntResolver(null).resolve()
).also {
it.otherId = id ?: IntResolver(it).resolve()
}
```
#### Classes declaration Map To
```kotlin
@KOMMMap(
to = [DestinationObject::class]
)
data class SourceObject(
@NullSubstitute(MapDefault(IntResolver::class))
val id: Int?
)
```
#### Generated extension function for Map To
```kotlin
fun SourceObject.toDestinationObject(): DestinationObject = DestinationObject(
id = id ?: IntResolver(null).resolve()
)
```
### Multi Sources Support
#### Classes declaration
```kotlin
@KOMMMap(
from = [FirstSourceObject::class, SecondSourceObject::class]
)
data class DestinationObject(
@NullSubstitute(MapDefault(IntResolver::class), [FirstSourceObject::class])
@MapName("userId", [SecondSourceObject::class])
val id: Int
) {
@NullSubstitute(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:
```kotlin
@KOMMMap(
from = [FirstSourceObject::class],
config = MapConfiguration(
allowNotNullAssertion = true
)
)
@KOMMMap(
from = [SecondSourceObject::class]
)
data class DestinationObject(
@NullSubstitute(MapDefault(IntResolver::class), [FirstSourceObject::class])
@MapName("userId", [SecondSourceObject::class])
val id: Int
) {
@NullSubstitute(MapDefault(IntResolver::class), "id", [FirstSourceObject::class])
var otherId: Int = 0
}
```
#### Generated extension functions
```kotlin
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
### Iterable Plugin - Collections Mapping
#### Add with Gradle###### JVM Project
```kotlin
plugins {
id("com.google.devtools.ksp") version "2.1.0-1.0.28"
}val kommVersion = "0.22.8"
depensencies {
implementation("com.ucasoft.komm:komm-annotations:$kommVersion")
ksp("com.ucasoft.komm:komm-processor:$kommVersion")
ksp("com.ucasoft.komm:komm-plugins-iterable:$kommVersion")
}
```
###### Multiplatform Project
```kotlin
plugins {
id("com.google.devtools.ksp") version "2.1.0-1.0.28"
}val kommVersion = "0.22.8"
//...
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.
}
```
#### Allow NotNullAssertion
###### Classes declaration
```kotlin
class SourceObject {
val intList: List? = listOf(1, 2, 3)
}@KOMMMap(from = [SourceObject::class], config = MapConfiguration(allowNotNullAssertion = true))
data class DestinationObject(
@MapName("intList")
val stringList: MutableList
)
```
###### Generated extension function
```kotlin
public fun SourceObject.toDestinationObject(): DestinationObject = DestinationObject(
stringList = intList!!.map { it.toString() }.toMutableList()
)
```
#### NullSubstitute
###### Classes declaration
```kotlin
class SourceObject {
val intList: List? = listOf(1, 2, 3)
}@KOMMMap(from = [SourceObject::class])
data class DestinationObject(
@NullSubstitute(MapDefault(StringListResolver::class), "intList")
val stringList: MutableList
)
```
###### Generated extension function
```kotlin
public fun SourceObject.toDestinationObject(): DestinationObject = DestinationObject(
stringList = intList?.map { it.toString() }?.toMutableList() ?: StringListResolver(null).resolve()
)
```### Exposed Plugin - ResultRow Mapping
#### Add with Gradle###### JVM Project
```kotlin
plugins {
id("com.google.devtools.ksp") version "2.1.0-1.0.28"
}val kommVersion = "0.22.8"
depensencies {
implementation("com.ucasoft.komm:komm-annotations:$kommVersion")
ksp("com.ucasoft.komm:komm-processor:$kommVersion")
ksp("com.ucasoft.komm:komm-plugins-exposed:$kommVersion")
}
```
#### Usage
###### Classes declaration
```kotlin
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
)
```
###### Generated extension function
```kotlin
public fun ResultRow.toDestinationObject(): DestinationObject = DestinationObject(
id = this[SourceObject.id],
name = this[SourceObject.name],
age = this[SourceObject.age]
)
```