mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#1057 documentation for Controlling forged name based bean mapping from root level with @Mapping
This commit is contained in:
parent
51e5976a7f
commit
582bbe4412
@ -0,0 +1,87 @@
|
||||
[[controlling-nested-bean-mappings]]
|
||||
=== Controlling nested bean mappings
|
||||
|
||||
As explained above, MapStruct will generate a method based on the name of the source and target property. Unfortunately, in many occasions these names do not match.
|
||||
|
||||
The ‘.’ notation in an `@Mapping` source or target type can be used to control how properties should be mapped when names do not match.
|
||||
There is an elaborate https://github.com/mapstruct/mapstruct-examples/tree/master/mapstruct-nested-bean-mappings[example] in our examples repository to explain how this problem can be overcome.
|
||||
|
||||
In the simplest scenario there’s a property on a nested level that needs to be corrected.
|
||||
Take for instance a property `fish` which has an identical name in `FishTankDto` and `FishTank`.
|
||||
For this property MapStruct automatically generates a mapping: `FishDto fishToFishDto(Fish fish)`.
|
||||
MapStruct cannot possibly be aware of the deviating properties `kind` and `type`.
|
||||
Therefore this can be addressed in a mapping rule: `@Mapping(target="fish.kind", source="fish.type")`.
|
||||
This tells MapStruct to deviate from looking for a name `kind` at this level and map it to `type`.
|
||||
|
||||
.Mapper controlling nested beans mappings I
|
||||
====
|
||||
[source, java, linenums]
|
||||
[subs="verbatim,attributes"]
|
||||
----
|
||||
@Mapper
|
||||
public interface FishTankMapper {
|
||||
|
||||
@Mappings({
|
||||
@Mapping(target = "fish.kind", source = "fish.type"),
|
||||
@Mapping(target = "fish.name", ignore = true),
|
||||
@Mapping(target = "ornament", source = "interior.ornament"),
|
||||
@Mapping(target = "material.materialType", source = "material"),
|
||||
@Mapping(target = "quality.report.organisation.name", source = "quality.report.organisationName")
|
||||
})
|
||||
FishTankDto map( FishTank source );
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
The same constructs can be used to ignore certain properties at a nesting level, as is demonstrated in the second `@Mapping` rule.
|
||||
|
||||
MapStruct can even be used to “cherry pick” properties when source and target do not share the same nesting level (the same number of properties).
|
||||
This can be done in the source – and in the target type. This is demonstrated in the next 2 rules: `@Mapping(target="ornament", source="interior.ornament")` and `@Mapping(target="material.materialType", source="material")`.
|
||||
|
||||
The latter can even be done when mappings first share a common base.
|
||||
For example: all properties that share the same name of `Quality` are mapped to `QualityDto`.
|
||||
Likewise, all properties of `Report` are mapped to `ReportDto`, with one exception: `organisation` in `OrganisationDto` is left empty (since there is no organization at the source level).
|
||||
Only the `name` is populated with the `organisationName` from `Report`.
|
||||
This is demonstrated in `@Mapping(target="quality.report.organisation.name", source="quality.report.organisationName")`
|
||||
|
||||
Coming back to the original example: what if `kind` and `type` would be beans themselves?
|
||||
In that case MapStruct would again generate a method continuing to map.
|
||||
Such is demonstrated in the next example:
|
||||
|
||||
|
||||
.Mapper controlling nested beans mappings II
|
||||
====
|
||||
[source, java, linenums]
|
||||
[subs="verbatim,attributes"]
|
||||
----
|
||||
@Mapper
|
||||
public interface FishTankMapperWithDocument {
|
||||
|
||||
@Mappings({
|
||||
@Mapping(target = "fish.kind", source = "fish.type"),
|
||||
@Mapping(target = "fish.name", expression = "java(\"Jaws\")"),
|
||||
@Mapping(target = "plant", ignore = true ),
|
||||
@Mapping(target = "ornament", ignore = true ),
|
||||
@Mapping(target = "material", ignore = true),
|
||||
@Mapping(target = "quality.document", source = "quality.report"),
|
||||
@Mapping(target = "quality.document.organisation.name", constant = "NoIdeaInc" )
|
||||
})
|
||||
FishTankWithNestedDocumentDto map( FishTank source );
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Note what happens in `@Mapping(target="quality.document", source="quality.report")`.
|
||||
`DocumentDto` does not exist as such on the target side. It is mapped from `Report`.
|
||||
MapStruct continues to generate mapping code here. That mapping it self can be guided towards another name.
|
||||
This even works for constants and expression. Which is shown in the final example: `@Mapping(target="quality.document.organisation.name", constant="NoIdeaInc")`.
|
||||
|
||||
MapStruct will perform a null check on each nested property in the source.
|
||||
|
||||
[TIP]
|
||||
====
|
||||
Instead of configuring everything via the parent method we encourage users to explicitly write their own nested methods.
|
||||
This puts the configuration of the nested mapping into one place (method) where it can be reused from several methods in the upper level,
|
||||
instead of re-configuring the same things on all of those upper methods.
|
||||
====
|
@ -466,36 +466,26 @@ Specifying the parameter in which the property resides is mandatory when using t
|
||||
Mapping methods with several source parameters will return `null` in case all the source parameters are `null`. Otherwise the target object will be instantiated and all properties from the provided parameters will be propagated.
|
||||
====
|
||||
|
||||
[[nested-mappings]]
|
||||
=== Nested mappings
|
||||
MapStruct also offers the possibility to directly refer to a source parameter.
|
||||
|
||||
MapStruct will handle nested mappings (in source), by means of the `.` notation:
|
||||
|
||||
.Mapping method with several source parameters
|
||||
.Mapping method directly referring to a source parameter
|
||||
====
|
||||
[source, java, linenums]
|
||||
[subs="verbatim,attributes"]
|
||||
----
|
||||
@Mappings({
|
||||
@Mapping(target = "chartName", source = "chart.name"),
|
||||
@Mapping(target = "title", source = "song.title"),
|
||||
@Mapping(target = "artistName", source = "song.artist.name"),
|
||||
@Mapping(target = "recordedAt", source = "song.artist.label.studio.name"),
|
||||
@Mapping(target = "city", source = "song.artist.label.studio.city"),
|
||||
@Mapping(target = "position", source = "position")
|
||||
})
|
||||
ChartEntry map(Chart chart, Song song, Integer position);
|
||||
@Mapper
|
||||
public interface AddressMapper {
|
||||
|
||||
@Mappings({
|
||||
@Mapping(source = "person.description", target = "description"),
|
||||
@Mapping(source = "hn", target = "houseNumber")
|
||||
})
|
||||
DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Integer hn);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Note: the parameter name (`chart`, `song`, `position`) is required, since there are several source parameters in the mapping. If there's only one source parameter, the parameter name can be ommited.
|
||||
|
||||
MapStruct will perform a null check on each nested property in the source.
|
||||
|
||||
[TIP]
|
||||
====
|
||||
Also non java bean source parameters (like the `java.lang.Integer`) can be mapped in this fashion.
|
||||
====
|
||||
In this case the source parameter is directly mapped into the target as the example above demonstrates. The parameter `hn`, a non bean type (in this case `java.lang.Integer`) is mapped to `houseNumber`.
|
||||
|
||||
[[updating-bean-instances]]
|
||||
=== Updating existing bean instances
|
||||
@ -827,6 +817,8 @@ When generating the implementation of a mapping method, MapStruct will apply the
|
||||
* If no such method was found MapStruct will try to generate an internal method that will do the mapping between the source and target attributes
|
||||
* If MapStruct could not create a name based mapping method an error will be raised at build time, indicating the non-mappable attribute and its path.
|
||||
|
||||
include::controlling-nested-bean-mappings.asciidoc[]
|
||||
|
||||
[[invoking-other-mappers]]
|
||||
=== Invoking other mappers
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user