Skip to content

Commit d1f707a

Browse files
committed
Update the README.md to improve clarity and introduce a new, more explicit API
1 parent 6e58968 commit d1f707a

1 file changed

Lines changed: 32 additions & 57 deletions

File tree

README.md

Lines changed: 32 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Kotlin AutoMapper uses KSP (Kotlin Symbol Processing) to generate extension func
1515
- **Visibility Control:** Control the visibility of generated extensions (`public` or `internal`) by setting the visibility of your `@AutoMapperModule` interface.
1616
- **Supports `data`, `enum`, and `sealed` classes:** Covers most mapping scenarios.
1717
- **Bidirectional & Unidirectional Mapping:** Generate mappings in one or both directions with a simple `reversible` flag.
18+
- **Customizable Default Values:** Provide default values for properties that are missing in the source or are `null`.
1819
- **Automatic Primitive Conversion:** Handles conversions like `String` to `Int`, `Int` to `Long`, etc., out of the box.
1920
- **Collection Mapping:** Automatically handles `List` and `Set` transformations.
2021
- **Zero Runtime Dependencies:** The `annotation` library is `SOURCE`-only, so it doesn't get bundled into your final artifact.
@@ -210,23 +211,21 @@ interface MapperModule {
210211
}
211212
```
212213

213-
### Mapping Properties with Different Names and Nullability
214+
### Customizing Mappings
214215

215-
A common scenario is that property names or nullability do not match between layers. AutoMapper handles this gracefully using the `propertyMappings` parameter.
216+
AutoMapper provides powerful annotations to handle mismatches in property names or to provide default values when a source property is missing or `null`.
216217

217-
You can provide an array of `@PropertyMapping` annotations to define custom rules:
218-
- Use `from` and `to` to map properties with different names.
219-
- Use `defaultValue` to provide a fallback for a `nullable` source property when the target property is not nullable. If the source name is the same as the target, you can omit the `to` parameter.
218+
#### Renaming Properties with `@PropertyMapping`
220219

221-
#### For Data Classes
220+
Use the `propertyMappings` array to map properties that have different names between the source and target. Both `from` and `to` parameters are mandatory.
222221

223222
*Models:*
224223
```kotlin
225-
// Domain: nullable address
226-
data class User(val id: Long, val address: String?)
224+
// Domain
225+
data class User(val id: Long, val fullName: String)
227226

228-
// Data Layer: different id name, non-nullable address
229-
data class UserEntity(val userId: Long, val address: String)
227+
// Data Layer
228+
data class UserEntity(val userId: Long, val name: String)
230229
```
231230

232231
*Mapping Definition:*
@@ -235,75 +234,51 @@ import io.github.jacksever.automapper.annotation.PropertyMapping
235234

236235
@AutoMapper(
237236
propertyMappings = [
238-
// Renames 'id' to 'userId'
239237
PropertyMapping(from = "id", to = "userId"),
240-
// Provides a default value for 'address' if it's null
241-
PropertyMapping(from = "address", defaultValue = "Unknown")
238+
PropertyMapping(from = "fullName", to = "name")
242239
]
243240
)
244241
fun userMapper(user: User): UserEntity
245242
```
246243

247-
The generated code will safely use the Elvis operator: `address = address ?: "Unknown"`.
248-
249-
#### For Enum Constants
250-
251-
The same principle applies to `enum` constants with different names.
252-
253-
*Models:*
254-
```kotlin
255-
// Domain
256-
enum class Status { PENDING, ... }
244+
This also works for renaming `enum` constants or `sealed` class implementations.
257245

258-
// UI
259-
enum class UiStatus { PENDING_APPROVAL, ... }
260-
```
261-
262-
*Mapping Definition:*
263-
```kotlin
264-
import io.github.jacksever.automapper.annotation.PropertyMapping
265-
266-
@AutoMapper(
267-
propertyMappings = [
268-
PropertyMapping(from = "PENDING", to = "PENDING_APPROVAL")
269-
]
270-
)
271-
fun statusMapper(status: Status): UiStatus
272-
```
246+
#### Providing Default Values with `@DefaultValue`
273247

274-
#### For Sealed Classes
248+
Use the `defaultValues` array to provide a fallback value for a target property. This is useful in two scenarios:
249+
1. The source class does not have a corresponding property.
250+
2. The source property is `nullable`, but the target property is not.
275251

276-
The `@PropertyMapping` annotation is powerful enough to handle both subclass names and the properties within them.
252+
The processor will generate code that uses the provided value if the source property is missing or `null`.
277253

278254
*Models:*
279255
```kotlin
280-
// Domain
281-
sealed interface Shape {
282-
283-
data class Ellipse(val majorAxis: Double, ...) : Shape
284-
}
256+
enum class Role { ADMIN, GUEST }
285257

286-
// UI
287-
sealed interface UiShape {
288-
289-
data class Oval(val uiMajorAxis: Double, ...) : UiShape
290-
}
258+
// Domain: nullable address, no role
259+
data class User(val id: Long, val address: String?)
260+
261+
// Data Layer: non-nullable address, has a role
262+
data class UserEntity(val id: Long, val address: String, val role: Role)
291263
```
292264

293265
*Mapping Definition:*
294266
```kotlin
295-
import io.github.jacksever.automapper.annotation.PropertyMapping
267+
import io.github.jacksever.automapper.annotation.DefaultValue
296268

297269
@AutoMapper(
298-
propertyMappings = [
299-
// Rule for the subclass name
300-
PropertyMapping(from = "Ellipse", to = "Oval"),
301-
// Rule for a property inside that subclass
302-
PropertyMapping(from = "majorAxis", to = "uiMajorAxis")
270+
defaultValues = [
271+
// Provides a value for 'role' (an enum) which is missing in the source
272+
DefaultValue(property = "role", value = "Role.GUEST"),
273+
// Provides a value for 'address' if it's null
274+
DefaultValue(property = "address", value = "Unknown")
303275
]
304276
)
305-
fun shapeMapper(shape: Shape): UiShape
277+
fun userMapper(user: User): UserEntity
306278
```
279+
The generated code will safely use the Elvis operator for `address` (`address = address ?: "Unknown"`) and will assign the enum constant for `role` (`role = Role.GUEST`).
280+
281+
The same approach works for `sealed class` objects. It's best to use the simple class name (e.g., `TaskState.Idle`), as the processor will automatically add the necessary imports.
307282

308283
## Compatibility
309284

0 commit comments

Comments
 (0)