mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
By default the constructor argument names are used to extract the target properties. If a constructor is annotated with an annotation named `@ConstructorProperties` (from any package) then it would be used to extract the target properties. If a mapping target has a parameterless empty constructor it would be used to instantiate the target. When there are multiple constructors then an annotation named `@Default` (from any package) can be used to mark a constructor that should be used by default when instantiating the target. Supports mapping into Java 14 Records and Kotlin data classes out of the box
608 lines
23 KiB
Plaintext
608 lines
23 KiB
Plaintext
[[defining-mapper]]
|
|
== Defining a mapper
|
|
|
|
In this section you'll learn how to define a bean mapper with MapStruct and which options you have to do so.
|
|
|
|
[[basic-mappings]]
|
|
=== Basic mappings
|
|
|
|
To create a mapper simply define a Java interface with the required mapping method(s) and annotate it with the `org.mapstruct.Mapper` annotation:
|
|
|
|
.Java interface to define a mapper
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
@Mapper
|
|
public interface CarMapper {
|
|
|
|
@Mapping(source = "make", target = "manufacturer")
|
|
@Mapping(source = "numberOfSeats", target = "seatCount")
|
|
CarDto carToCarDto(Car car);
|
|
|
|
@Mapping(source = "name", target = "fullName")
|
|
PersonDto personToPersonDto(Person person);
|
|
}
|
|
----
|
|
====
|
|
|
|
The `@Mapper` annotation causes the MapStruct code generator to create an implementation of the `CarMapper` interface during build-time.
|
|
|
|
In the generated method implementations all readable properties from the source type (e.g. `Car`) will be copied into the corresponding property in the target type (e.g. `CarDto`):
|
|
|
|
* When a property has the same name as its target entity counterpart, it will be mapped implicitly.
|
|
* When a property has a different name in the target entity, its name can be specified via the `@Mapping` annotation.
|
|
|
|
[TIP]
|
|
====
|
|
The property name as defined in the http://www.oracle.com/technetwork/java/javase/documentation/spec-136004.html[JavaBeans specification] must be specified in the `@Mapping` annotation, e.g. _seatCount_ for a property with the accessor methods `getSeatCount()` and `setSeatCount()`.
|
|
====
|
|
[TIP]
|
|
====
|
|
By means of the `@BeanMapping(ignoreByDefault = true)` the default behavior will be *explicit mapping*, meaning that all mappings have to be specified by means of the `@Mapping` and no warnings will be issued on missing target properties.
|
|
====
|
|
[TIP]
|
|
====
|
|
Fluent setters are also supported.
|
|
Fluent setters are setters that return the same type as the type being modified.
|
|
|
|
E.g.
|
|
|
|
```
|
|
public Builder seatCount(int seatCount) {
|
|
this.seatCount = seatCount;
|
|
return this;
|
|
}
|
|
```
|
|
====
|
|
|
|
|
|
To get a better understanding of what MapStruct does have a look at the following implementation of the `carToCarDto()` method as generated by MapStruct:
|
|
|
|
.Code generated by MapStruct
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
// GENERATED CODE
|
|
public class CarMapperImpl implements CarMapper {
|
|
|
|
@Override
|
|
public CarDto carToCarDto(Car car) {
|
|
if ( car == null ) {
|
|
return null;
|
|
}
|
|
|
|
CarDto carDto = new CarDto();
|
|
|
|
if ( car.getFeatures() != null ) {
|
|
carDto.setFeatures( new ArrayList<String>( car.getFeatures() ) );
|
|
}
|
|
carDto.setManufacturer( car.getMake() );
|
|
carDto.setSeatCount( car.getNumberOfSeats() );
|
|
carDto.setDriver( personToPersonDto( car.getDriver() ) );
|
|
carDto.setPrice( String.valueOf( car.getPrice() ) );
|
|
if ( car.getCategory() != null ) {
|
|
carDto.setCategory( car.getCategory().toString() );
|
|
}
|
|
carDto.setEngine( engineToEngineDto( car.getEngine() ) );
|
|
|
|
return carDto;
|
|
}
|
|
|
|
@Override
|
|
public PersonDto personToPersonDto(Person person) {
|
|
//...
|
|
}
|
|
|
|
private EngineDto engineToEngineDto(Engine engine) {
|
|
if ( engine == null ) {
|
|
return null;
|
|
}
|
|
|
|
EngineDto engineDto = new EngineDto();
|
|
|
|
engineDto.setHorsePower(engine.getHorsePower());
|
|
engineDto.setFuel(engine.getFuel());
|
|
|
|
return engineDto;
|
|
}
|
|
}
|
|
----
|
|
====
|
|
|
|
The general philosophy of MapStruct is to generate code which looks as much as possible as if you had written it yourself from hand. In particular this means that the values are copied from source to target by plain getter/setter invocations instead of reflection or similar.
|
|
|
|
As the example shows the generated code takes into account any name mappings specified via `@Mapping`.
|
|
If the type of a mapped attribute is different in source and target entity,
|
|
MapStruct will either apply an automatic conversion (as e.g. for the _price_ property, see also <<implicit-type-conversions>>)
|
|
or optionally invoke / create another mapping method (as e.g. for the _driver_ / _engine_ property, see also <<mapping-object-references>>).
|
|
MapStruct will only create a new mapping method if and only if the source and target property are properties of a Bean and they themselves are Beans or simple properties.
|
|
i.e. they are not `Collection` or `Map` type properties.
|
|
|
|
Collection-typed attributes with the same element type will be copied by creating a new instance of the target collection type containing the elements from the source property. For collection-typed attributes with different element types each element will be mapped individually and added to the target collection (see <<mapping-collections>>).
|
|
|
|
MapStruct takes all public properties of the source and target types into account. This includes properties declared on super-types.
|
|
|
|
[[mapping-composition]]
|
|
=== Mapping Composition (experimental)
|
|
MapStruct supports the use of meta annotations. The `@Mapping` annotation supports now `@Target` with `ElementType#ANNOTATION_TYPE` in addition to `ElementType#METHOD`. This allows `@Mapping` to be used on other (user defined) annotations for re-use purposes. For example:
|
|
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
@Retention(RetentionPolicy.CLASS)
|
|
@Mapping(target = "id", ignore = true)
|
|
@Mapping(target = "creationDate", expression = "java(new java.util.Date())")
|
|
@Mapping(target = "name", source = "groupName")
|
|
public @interface ToEntity { }
|
|
----
|
|
====
|
|
|
|
Can be used to characterise an `Entity` without the need to have a common base type. For instance, `ShelveEntity` and `BoxEntity` do not share a common base type in the `StorageMapper` below.
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
@Mapper
|
|
public interface StorageMapper {
|
|
|
|
StorageMapper INSTANCE = Mappers.getMapper( StorageMapper.class );
|
|
|
|
@ToEntity
|
|
@Mapping( target = "weightLimit", source = "maxWeight")
|
|
ShelveEntity map(ShelveDto source);
|
|
|
|
@ToEntity
|
|
@Mapping( target = "label", source = "designation")
|
|
BoxEntity map(BoxDto source);
|
|
}
|
|
----
|
|
====
|
|
|
|
Still, they do have some properties in common. The `@ToEntity` assumes both target beans `ShelveEntity` and `BoxEntity` have properties: `"id"`, `"creationDate"` and `"name"`. It furthermore assumes that the source beans `ShelveDto` and `BoxDto` always have a property `"groupName"`. This concept is also known as "duck-typing". In other words, if it quacks like duck, walks like a duck its probably a duck.
|
|
|
|
This feature is still experimental. Error messages are not mature yet: the method on which the problem occurs is displayed, as well as the concerned values in the `@Mapping` annotation. However, the composition aspect is not visible. The messages are "as if" the `@Mapping` would be present on the concerned method directly.
|
|
Therefore, the user should use this feature with care, especially when uncertain when a property is always present.
|
|
|
|
A more typesafe (but also more verbose) way would be to define base classes / interfaces on the target bean and the source bean and use `@InheritConfiguration` to achieve the same result (see <<mapping-configuration-inheritance>>).
|
|
|
|
[[adding-custom-methods]]
|
|
=== Adding custom methods to mappers
|
|
|
|
In some cases it can be required to manually implement a specific mapping from one type to another which can't be generated by MapStruct. One way to handle this is to implement the custom method on another class which then is used by mappers generated by MapStruct (see <<invoking-other-mappers>>).
|
|
|
|
Alternatively, when using Java 8 or later, you can implement custom methods directly in a mapper interface as default methods. The generated code will invoke the default methods if the argument and return types match.
|
|
|
|
As an example let's assume the mapping from `Person` to `PersonDto` requires some special logic which can't be generated by MapStruct. You could then define the mapper from the previous example like this:
|
|
|
|
.Mapper which defines a custom mapping with a default method
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
@Mapper
|
|
public interface CarMapper {
|
|
|
|
@Mapping(...)
|
|
...
|
|
CarDto carToCarDto(Car car);
|
|
|
|
default PersonDto personToPersonDto(Person person) {
|
|
//hand-written mapping logic
|
|
}
|
|
}
|
|
----
|
|
====
|
|
|
|
The class generated by MapStruct implements the method `carToCarDto()`. The generated code in `carToCarDto()` will invoke the manually implemented `personToPersonDto()` method when mapping the `driver` attribute.
|
|
|
|
A mapper could also be defined in the form of an abstract class instead of an interface and implement the custom methods directly in the mapper class. In this case MapStruct will generate an extension of the abstract class with implementations of all abstract methods. An advantage of this approach over declaring default methods is that additional fields could be declared in the mapper class.
|
|
|
|
The previous example where the mapping from `Person` to `PersonDto` requires some special logic could then be defined like this:
|
|
|
|
.Mapper defined by an abstract class
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
@Mapper
|
|
public abstract class CarMapper {
|
|
|
|
@Mapping(...)
|
|
...
|
|
public abstract CarDto carToCarDto(Car car);
|
|
|
|
public PersonDto personToPersonDto(Person person) {
|
|
//hand-written mapping logic
|
|
}
|
|
}
|
|
----
|
|
====
|
|
|
|
MapStruct will generate a sub-class of `CarMapper` with an implementation of the `carToCarDto()` method as it is declared abstract. The generated code in `carToCarDto()` will invoke the manually implemented `personToPersonDto()` method when mapping the `driver` attribute.
|
|
|
|
[[mappings-with-several-source-parameters]]
|
|
=== Mapping methods with several source parameters
|
|
|
|
MapStruct also supports mapping methods with several source parameters. This is useful e.g. in order to combine several entities into one data transfer object. The following shows an example:
|
|
|
|
.Mapping method with several source parameters
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
@Mapper
|
|
public interface AddressMapper {
|
|
|
|
@Mapping(source = "person.description", target = "description")
|
|
@Mapping(source = "address.houseNo", target = "houseNumber")
|
|
DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Address address);
|
|
}
|
|
----
|
|
====
|
|
|
|
The shown mapping method takes two source parameters and returns a combined target object. As with single-parameter mapping methods properties are mapped by name.
|
|
|
|
In case several source objects define a property with the same name, the source parameter from which to retrieve the property must be specified using the `@Mapping` annotation as shown for the `description` property in the example. An error will be raised when such an ambiguity is not resolved. For properties which only exist once in the given source objects it is optional to specify the source parameter's name as it can be determined automatically.
|
|
|
|
[WARNING]
|
|
====
|
|
Specifying the parameter in which the property resides is mandatory when using the `@Mapping` annotation.
|
|
====
|
|
|
|
[TIP]
|
|
====
|
|
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.
|
|
====
|
|
|
|
MapStruct also offers the possibility to directly refer to a source parameter.
|
|
|
|
.Mapping method directly referring to a source parameter
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
@Mapper
|
|
public interface AddressMapper {
|
|
|
|
@Mapping(source = "person.description", target = "description")
|
|
@Mapping(source = "hn", target = "houseNumber")
|
|
DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Integer hn);
|
|
}
|
|
----
|
|
====
|
|
|
|
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`.
|
|
|
|
[[mapping-nested-bean-properties-to-current-target]]
|
|
=== Mapping nested bean properties to current target
|
|
|
|
If you don't want explicitly name all properties from nested source bean, you can use `.` as target.
|
|
This will tell MapStruct to map every property from source bean to target object. The following shows an example:
|
|
|
|
.use of "target this" annotation "."
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
@Mapper
|
|
public interface CustomerMapper {
|
|
|
|
@Mapping( target = "name", source = "record.name" )
|
|
@Mapping( target = ".", source = "record" )
|
|
@Mapping( target = ".", source = "account" )
|
|
Customer customerDtoToCustomer(CustomerDto customerDto);
|
|
}
|
|
----
|
|
====
|
|
|
|
The generated code will map every property from `CustomerDto.record` to `Customer` directly, without need to manually name any of them.
|
|
The same goes for `Customer.account`.
|
|
|
|
When there are conflicts, these can be resolved by explicitely defining the mapping. For instance in the example above. `name` occurs in `CustomerDto.record` and in `CustomerDto.account`. The mapping `@Mapping( target = "name", source = "record.name" )` resolves this conflict.
|
|
|
|
|
|
This "target this" notation can be very useful when mapping hierarchical objects to flat objects and vice versa (`@InheritInverseConfiguration`).
|
|
|
|
|
|
|
|
[[updating-bean-instances]]
|
|
=== Updating existing bean instances
|
|
|
|
In some cases you need mappings which don't create a new instance of the target type but instead update an existing instance of that type. This sort of mapping can be realized by adding a parameter for the target object and marking this parameter with `@MappingTarget`. The following shows an example:
|
|
|
|
.Update method
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
@Mapper
|
|
public interface CarMapper {
|
|
|
|
void updateCarFromDto(CarDto carDto, @MappingTarget Car car);
|
|
}
|
|
----
|
|
====
|
|
|
|
The generated code of the `updateCarFromDto()` method will update the passed `Car` instance with the properties from the given `CarDto` object. There may be only one parameter marked as mapping target. Instead of `void` you may also set the method's return type to the type of the target parameter, which will cause the generated implementation to update the passed mapping target and return it as well. This allows for fluent invocations of mapping methods.
|
|
|
|
For `CollectionMappingStrategy.ACCESSOR_ONLY` Collection- or map-typed properties of the target bean to be updated will be cleared and then populated with the values from the corresponding source collection or map. Otherwise, For `CollectionMappingStrategy.ADDER_PREFERRED` or `CollectionMappingStrategy.TARGET_IMMUTABLE` the target will not be cleared and the values will be populated immediately.
|
|
|
|
[[direct-field-mappings]]
|
|
=== Mappings with direct field access
|
|
|
|
MapStruct also supports mappings of `public` fields that have no getters/setters. MapStruct will
|
|
use the fields as read/write accessor if it cannot find suitable getter/setter methods for the property.
|
|
|
|
A field is considered as a read accessor if it is `public` or `public final`. If a field is `static` it is not
|
|
considered as a read accessor.
|
|
|
|
A field is considered as a write accessor only if it is `public`. If a field is `final` and/or `static` it is not
|
|
considered as a write accessor.
|
|
|
|
Small example:
|
|
|
|
.Example classes for mapping
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
public class Customer {
|
|
|
|
private Long id;
|
|
private String name;
|
|
|
|
//getters and setter omitted for brevity
|
|
}
|
|
|
|
public class CustomerDto {
|
|
|
|
public Long id;
|
|
public String customerName;
|
|
}
|
|
|
|
@Mapper
|
|
public interface CustomerMapper {
|
|
|
|
CustomerMapper INSTANCE = Mappers.getMapper( CustomerMapper.class );
|
|
|
|
@Mapping(source = "customerName", target = "name")
|
|
Customer toCustomer(CustomerDto customerDto);
|
|
|
|
@InheritInverseConfiguration
|
|
CustomerDto fromCustomer(Customer customer);
|
|
}
|
|
----
|
|
====
|
|
|
|
For the configuration from above, the generated mapper looks like:
|
|
|
|
.Generated mapper for example classes
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
// GENERATED CODE
|
|
public class CustomerMapperImpl implements CustomerMapper {
|
|
|
|
@Override
|
|
public Customer toCustomer(CustomerDto customerDto) {
|
|
// ...
|
|
customer.setId( customerDto.id );
|
|
customer.setName( customerDto.customerName );
|
|
// ...
|
|
}
|
|
|
|
@Override
|
|
public CustomerDto fromCustomer(Customer customer) {
|
|
// ...
|
|
customerDto.id = customer.getId();
|
|
customerDto.customerName = customer.getName();
|
|
// ...
|
|
}
|
|
}
|
|
----
|
|
====
|
|
|
|
You can find the complete example in the
|
|
https://github.com/mapstruct/mapstruct-examples/tree/master/mapstruct-field-mapping[mapstruct-examples-field-mapping]
|
|
project on GitHub.
|
|
|
|
[[mapping-with-builders]]
|
|
=== Using builders
|
|
|
|
MapStruct also supports mapping of immutable types via builders.
|
|
When performing a mapping MapStruct checks if there is a builder for the type being mapped.
|
|
This is done via the `BuilderProvider` SPI.
|
|
If a Builder exists for a certain type, then that builder will be used for the mappings.
|
|
|
|
The default implementation of the `BuilderProvider` assumes the following:
|
|
|
|
* The type has a parameterless public static builder creation method that returns a builder.
|
|
So for example `Person` has a public static method that returns `PersonBuilder`.
|
|
* The builder type has a parameterless public method (build method) that returns the type being built.
|
|
In our example `PersonBuilder` has a method returning `Person`.
|
|
* In case there are multiple build methods, MapStruct will look for a method called `build`, if such method exists
|
|
then this would be used, otherwise a compilation error would be created.
|
|
* A specific build method can be defined by using `@Builder` within: `@BeanMapping`, `@Mapper` or `@MapperConfig`
|
|
* In case there are multiple builder creation methods that satisfy the above conditions then a `MoreThanOneBuilderCreationMethodException`
|
|
will be thrown from the `DefaultBuilderProvider` SPI.
|
|
In case of a `MoreThanOneBuilderCreationMethodException` MapStruct will write a warning in the compilation and not use any builder.
|
|
|
|
If such type is found then MapStruct will use that type to perform the mapping to (i.e. it will look for setters into that type).
|
|
To finish the mapping MapStruct generates code that will invoke the build method of the builder.
|
|
|
|
[NOTE]
|
|
======
|
|
Builder detection can be switched off by means of `@Builder#disableBuilder`. MapStruct will fall back on regular getters / setters in case builders are disabled.
|
|
======
|
|
|
|
[NOTE]
|
|
======
|
|
The <<object-factories>> are also considered for the builder type.
|
|
E.g. If an object factory exists for our `PersonBuilder` then this factory would be used instead of the builder creation method.
|
|
======
|
|
|
|
.Person with Builder example
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
public class Person {
|
|
|
|
private final String name;
|
|
|
|
protected Person(Person.Builder builder) {
|
|
this.name = builder.name;
|
|
}
|
|
|
|
public static Person.Builder builder() {
|
|
return new Person.Builder();
|
|
}
|
|
|
|
public static class Builder {
|
|
|
|
private String name;
|
|
|
|
public Builder name(String name) {
|
|
this.name = name;
|
|
return this;
|
|
}
|
|
|
|
public Person create() {
|
|
return new Person( this );
|
|
}
|
|
}
|
|
}
|
|
----
|
|
====
|
|
|
|
.Person Mapper definition
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
public interface PersonMapper {
|
|
|
|
Person map(PersonDto dto);
|
|
}
|
|
----
|
|
====
|
|
|
|
.Generated mapper with builder
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
// GENERATED CODE
|
|
public class PersonMapperImpl implements PersonMapper {
|
|
|
|
public Person map(PersonDto dto) {
|
|
if (dto == null) {
|
|
return null;
|
|
}
|
|
|
|
Person.Builder builder = Person.builder();
|
|
|
|
builder.name( dto.getName() );
|
|
|
|
return builder.create();
|
|
}
|
|
}
|
|
----
|
|
====
|
|
|
|
Supported builder frameworks:
|
|
|
|
* https://projectlombok.org/[Lombok] - requires having the Lombok classes in a separate module. See for more information https://github.com/rzwitserloot/lombok/issues/1538[rzwitserloot/lombok#1538]
|
|
* https://github.com/google/auto/blob/master/value/userguide/index.md[AutoValue]
|
|
* https://immutables.github.io/[Immutables] - When Immutables are present on the annotation processor path then the `ImmutablesAccessorNamingStrategy` and `ImmutablesBuilderProvider` would be used by default
|
|
* https://github.com/google/FreeBuilder[FreeBuilder] - When FreeBuilder is present on the annotation processor path then the `FreeBuilderAccessorNamingStrategy` would be used by default.
|
|
When using FreeBuilder then the JavaBean convention should be followed, otherwise MapStruct won't recognize the fluent getters.
|
|
* It also works for custom builders (handwritten ones) if the implementation supports the defined rules for the default `BuilderProvider`.
|
|
Otherwise, you would need to write a custom `BuilderProvider`
|
|
|
|
[TIP]
|
|
====
|
|
In case you want to disable using builders then you can use the `NoOpBuilderProvider` by creating a `org.mapstruct.ap.spi.BuilderProvider` file in the `META-INF/services` directory with `org.mapstruct.ap.spi.NoOpBuilderProvider` as it's content.
|
|
====
|
|
|
|
[[mapping-with-constructors]]
|
|
=== Using Constructors
|
|
|
|
MapStruct supports using constructors for mapping target types.
|
|
When doing a mapping MapStruct checks if there is a builder for the type being mapped.
|
|
If there is no builder, then MapStruct looks for a single accessible constructor.
|
|
When there are multiple constructors then the following is done to pick the one which should be used:
|
|
|
|
* If a parameterless constructor exists then it would be used to construct the object, and the other constructors will be ignored
|
|
* If there are multiple constructors then the one annotated with annotation named `@Default` (from any package) will be used
|
|
|
|
When using a constructor then the names of the parameters of the constructor will be used and matched to the target properties.
|
|
When the constructor has an annotation named `@ConstructorProperties` (from any package) then this annotation will be used to get the names of the parameters.
|
|
|
|
[NOTE]
|
|
====
|
|
When an object factory method or a method annotated with `@ObjectFactory` exists, it will take precedence over any constructor defined in the target.
|
|
The target object constructor will not be used in that case.
|
|
====
|
|
|
|
|
|
.Person with constructor parameters
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
public class Person {
|
|
|
|
private final String name;
|
|
private final String surname;
|
|
|
|
public Person(String name, String surname) {
|
|
this.name = name;
|
|
this.surname = surname;
|
|
}
|
|
}
|
|
----
|
|
====
|
|
|
|
.Person With Constructor Mapper definition
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
public interface PersonMapper {
|
|
|
|
Person map(PersonDto dto);
|
|
}
|
|
----
|
|
====
|
|
|
|
.Generated mapper with constructor
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
// GENERATED CODE
|
|
public class PersonMapperImpl implements PersonMapper {
|
|
|
|
public Person map(PersonDto dto) {
|
|
if (dto == null) {
|
|
return null;
|
|
}
|
|
|
|
String name;
|
|
String surname;
|
|
name = dto.getName();
|
|
surname = dto.getSurname();
|
|
|
|
Person person = new Person( name, surname );
|
|
|
|
return person;
|
|
}
|
|
}
|
|
----
|
|
====
|