Mappie supports defining local conversion methods inside your mapper classes that are automatically discovered and used when type conversion is needed. This provides a simpler alternative to creating separate mapper classes for simple type conversions.
Basic Usage #
Suppose we have a wrapper type StringWrapper and want to map it to a String:
data class StringWrapper(val value: String)
data class Person(val name: StringWrapper)
data class PersonDto(val name: String)
Instead of creating a separate ObjectMappie<StringWrapper, String>, you can define a conversion method directly in
your mapper:
object PersonMapper : ObjectMappie<Person, PersonDto>() {
fun unwrap(wrapper: StringWrapper): String = wrapper.value
override fun map(from: Person) = mapping()
}
Mappie will automatically discover the unwrap method and use it when it needs to convert StringWrapper to String.
Method Requirements #
A method is recognized as a local conversion method if it:
- Takes exactly one parameter
- Returns a type different from the parameter type
- Is not one of Mappie's own methods (
map,mapNullable,mapList, etc.)
The method can have any name - it doesn't need to be called map.
Reusable Conversions via Interfaces #
For maximum reuse, you can define conversion methods in an interface and implement it in multiple mappers:
interface CommonConverters {
fun unwrap(wrapper: StringWrapper): String = wrapper.value
fun unwrapInt(wrapper: IntWrapper): Int = wrapper.value
}
object PersonMapper : ObjectMappie<Person, PersonDto>(), CommonConverters {
override fun map(from: Person) = mapping()
}
object EmployeeMapper : ObjectMappie<Employee, EmployeeDto>(), CommonConverters {
override fun map(from: Employee) = mapping()
}
Both mappers will automatically use the conversion methods defined in CommonConverters.
Generic Conversion Methods #
Local conversion methods can also be generic:
data class Input(val items: List<String>)
data class Output(val items: Set<String>)
object Mapper : ObjectMappie<Input, Output>() {
fun <T> toSet(list: List<T>): Set<T> = list.toSet()
override fun map(from: Input) = mapping()
}
Excluding Methods #
If you have a method that matches the conversion method signature but should not be used for automatic conversion,
annotate it with @ExcludeFromMapping:
import tech.mappie.api.config.ExcludeFromMapping
object PersonMapper : ObjectMappie<Person, PersonDto>() {
@ExcludeFromMapping
fun validateWrapper(wrapper: StringWrapper): String {
require(wrapper.value.isNotBlank())
return wrapper.value
}
override fun map(from: Person) = mapping {
PersonDto::name fromProperty Person::name transform { it.value }
}
}
This is useful when you have utility methods that happen to take one parameter and return a different type, but should not be used as automatic conversion methods.
Priority #
When multiple conversion options are available, Mappie uses the following priority order:
- Local conversion methods defined in the mapper class itself
- Conversion methods inherited from interfaces
- Other
ObjectMappiemappers (internal or external) - Built-in mappers
This means local conversion methods will take precedence over built-in mappers, allowing you to override default behavior when needed.
Comparison with Via Operator #
Local conversion methods are ideal for:
- Simple type unwrapping/wrapping
- Conversions that don't require the full power of
ObjectMappie - Reusable conversions shared across multiple mappers via interfaces
The via operator is better suited for:
- Complex object-to-object mappings
- Cases where you need explicit control over which mapper to use
- Nested object mappings with their own mapping logic