109 lines
2.8 KiB
Markdown
109 lines
2.8 KiB
Markdown
|
# Object Mapping
|
||
|
|
||
|
**Status:**
|
||
|
- [x] proposed by Michael Hönnig
|
||
|
- [ ] accepted by (Participants)
|
||
|
- [ ] rejected by (Participants)
|
||
|
- [ ] superseded by (superseding ADR)
|
||
|
|
||
|
## Context and Problem Statement
|
||
|
|
||
|
Since we are using the *API first*-approach,
|
||
|
thus generating Java interfaces and model classes from an OpenAPI specification,
|
||
|
we cannot use the JPA-entities anymore at the API level,
|
||
|
not even if the data fields are 100% identical.
|
||
|
|
||
|
Therefore, we need some kind of mapping strategy.
|
||
|
|
||
|
|
||
|
### Technical Background
|
||
|
|
||
|
Java does not support duck-typing and therefore, objects of different classes have to be converted to each other, even if all data fields are identical.
|
||
|
|
||
|
In our case, the database query is usually the slowest part of handling a request.
|
||
|
Therefore, for the mapper, ease of use is more important than performance,
|
||
|
at least as long as the mapping part does not take more than 10% of the total request.
|
||
|
|
||
|
|
||
|
## Considered Options
|
||
|
|
||
|
* specific programmatic conversion
|
||
|
* using the *MapStruct* library
|
||
|
* using the *ModelMapper* library
|
||
|
* Dozer, last update from 2014 + vulnerabilities => skipped
|
||
|
* Orika, last update from 2019 + vulnerabilities => skipped
|
||
|
* JMapper
|
||
|
|
||
|
### specific programmatic conversion
|
||
|
|
||
|
In this solution, we would write own code to convert the objects.
|
||
|
This usually means 3 converters for each entity/resource pair:
|
||
|
|
||
|
- entity -> resource
|
||
|
- resource -> entity
|
||
|
- list of entities -> list of resources
|
||
|
|
||
|
#### Advantages
|
||
|
|
||
|
Very flexible and fast.
|
||
|
|
||
|
#### Disadvantages
|
||
|
|
||
|
Huge amounts of bloat code.
|
||
|
|
||
|
|
||
|
### using the *MapStruct* library
|
||
|
|
||
|
See https://mapstruct.org/.
|
||
|
|
||
|
#### Advantages
|
||
|
|
||
|
- Most popular mapping library in the Java-world.
|
||
|
- Actively maintained, last release 1.5.2 from Jun 18, 2022.
|
||
|
- very fast (see [^1])
|
||
|
|
||
|
|
||
|
#### Disadvantages
|
||
|
|
||
|
- Needs interface declarations with annotations.
|
||
|
- Looks like it causes still too much bloat code for our purposes.
|
||
|
|
||
|
|
||
|
### using the *ModelMapper* library
|
||
|
|
||
|
See http://modelmapper.org/.
|
||
|
|
||
|
#### Advantages
|
||
|
|
||
|
- 1:1 mappings just need a simple method call without any bloat-code.
|
||
|
- Actively maintained, last release 3.1.0 from Mar 08, 2022.
|
||
|
|
||
|
#### Disadvantages
|
||
|
|
||
|
- could not find any, will give it a try
|
||
|
|
||
|
### using the *JMapper* library
|
||
|
|
||
|
See https://jmapper-framework.github.io/jmapper-core/.
|
||
|
|
||
|
#### Advantages
|
||
|
|
||
|
- Supports annotation-based and programmatic mapping exceptions.
|
||
|
- Actively maintained, last release 1.6.3 from May 27, 2022.
|
||
|
- very fast (see [^1])
|
||
|
|
||
|
|
||
|
#### Disadvantages
|
||
|
|
||
|
- needs a separate mapper instance for each mapping pair
|
||
|
- cannot map collections (needs `stream().map(...).collect(toList())` or similar)
|
||
|
|
||
|
|
||
|
## Decision Outcome
|
||
|
|
||
|
We chose the option **"using the *ModelMapper* library"** because it has an acceptable performance without any bloat code.
|
||
|
|
||
|
If it turns out to be too slow after all, "using the *JMapper* library" seems to be a good alternative.
|
||
|
|
||
|
[^1]: https://www.baeldung.com/java-performance-mapping-frameworks
|