Basic Mapping¶
This page covers the core mapping annotations and how Kraft matches properties between source and target classes.
@MapConfig¶
@MapConfig is placed on a standalone object and references both source and target externally. This keeps mapping logic separate from your data classes.
import com.blu3berry.kraft.config.MapConfig
data class User(val name: String, val age: Int)
data class UserDto(val name: String, val age: Int)
@MapConfig(
source = User::class,
target = UserDto::class,
)
object UserMapper
Generated output:
Property matching is by name and type. Every target constructor parameter that shares a name and type with a source property is mapped automatically.
@MapFrom¶
@MapFrom is placed on the target class. The source parameter specifies the class to map from.
import com.blu3berry.kraft.mapping.MapFrom
data class User(val name: String, val age: Int)
@MapFrom(User::class)
data class UserDto(val name: String, val age: Int)
Generated output:
@MapTo¶
@MapTo is placed on the source class. The target parameter specifies the class to map to.
import com.blu3berry.kraft.mapping.MapTo
@MapTo(UserDto::class)
data class User(val name: String, val age: Int)
data class UserDto(val name: String, val age: Int)
Generated output (identical to the @MapFrom example above):
When to Use Which¶
| Scenario | Recommended annotation |
|---|---|
| You want mapping logic separate from data classes | @MapConfig on an object |
| You own neither class, or they are generated/third-party | @MapConfig on an object |
| You own the target class (typical DTO pattern) | @MapFrom on the target |
| You own the source class | @MapTo on the source |
All three produce the same generated code. The difference is only where the annotation lives. You cannot place both @MapFrom and @MapTo on the same class -- doing so results in a compile-time error.
Properties with Default Values¶
Target properties that have a default value and no matching source property are automatically omitted from the generated constructor call, so Kotlin uses the default. No ignore annotation is needed in this case, and Kraft reports nothing.
data class PersonSource(val name: String)
data class PersonDto(
val name: String,
val score: Int = 0 // no matching source property -- uses default
)
@MapConfig(source = PersonSource::class, target = PersonDto::class)
object PersonMapper
Generated output (score is omitted, so PersonSource("Ada").toPersonDto() is PersonDto(name = "Ada", score = 0)):
Nullable properties without a default¶
A nullable target property with no matching source property and no default gets null:
data class PersonDto(
val name: String,
val nickname: String? // no matching source property, no default
)
Kraft also warns with KRAFT-W009, because a renamed source property would otherwise turn into a silent null. Write val nickname: String? = null to make null the intended value. The property is then omitted like any other defaulted property, and the warning goes away.
@MapIgnore¶
Use @MapIgnore to explicitly skip a target property when using @MapFrom or @MapTo. The property must declare a default value (e.g. = null for nullable types) since Kraft will not supply a value for it. For the config-based equivalent, see Ignore Rules.
import com.blu3berry.kraft.mapping.MapFrom
import com.blu3berry.kraft.mapping.MapIgnore
data class ProductSource(val name: String, val price: Double)
@MapFrom(ProductSource::class)
data class ProductDto(
val name: String,
@MapIgnore
val price: Double = 0.0
)
Generated output:
Error Cases¶
Missing source property with no default: If the target has a non-nullable constructor parameter without a default value and there is no matching source property, Kraft reports a compile-time error.
Type mismatch: If a source property and target property share the same name but have incompatible types, Kraft reports a compile-time error. Use a field rename or converter to handle this situation.
See Also¶
- Configuration Objects -- an alternative way to declare mappings without annotating the classes themselves.
- Field Renaming -- mapping properties with different names.
- Nested Mapping -- mapping properties that contain other mapped types.