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.
|
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]]
|
MapStruct also offers the possibility to directly refer to a source parameter.
|
||||||
=== Nested mappings
|
|
||||||
|
|
||||||
MapStruct will handle nested mappings (in source), by means of the `.` notation:
|
.Mapping method directly referring to a source parameter
|
||||||
|
|
||||||
.Mapping method with several source parameters
|
|
||||||
====
|
====
|
||||||
[source, java, linenums]
|
[source, java, linenums]
|
||||||
[subs="verbatim,attributes"]
|
[subs="verbatim,attributes"]
|
||||||
----
|
----
|
||||||
@Mappings({
|
@Mapper
|
||||||
@Mapping(target = "chartName", source = "chart.name"),
|
public interface AddressMapper {
|
||||||
@Mapping(target = "title", source = "song.title"),
|
|
||||||
@Mapping(target = "artistName", source = "song.artist.name"),
|
@Mappings({
|
||||||
@Mapping(target = "recordedAt", source = "song.artist.label.studio.name"),
|
@Mapping(source = "person.description", target = "description"),
|
||||||
@Mapping(target = "city", source = "song.artist.label.studio.city"),
|
@Mapping(source = "hn", target = "houseNumber")
|
||||||
@Mapping(target = "position", source = "position")
|
})
|
||||||
})
|
DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Integer hn);
|
||||||
ChartEntry map(Chart chart, Song song, Integer position);
|
}
|
||||||
----
|
----
|
||||||
====
|
====
|
||||||
|
|
||||||
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.
|
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`.
|
||||||
|
|
||||||
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.
|
|
||||||
====
|
|
||||||
|
|
||||||
[[updating-bean-instances]]
|
[[updating-bean-instances]]
|
||||||
=== Updating existing 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 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.
|
* 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]]
|
||||||
=== Invoking other mappers
|
=== Invoking other mappers
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user