mapstruct/documentation/src/main/asciidoc/chapter-4-retrieving-a-mapper.asciidoc
2021-01-17 15:13:42 +01:00

129 lines
4.7 KiB
Plaintext

[[retrieving-mapper]]
== Retrieving a mapper
[[mappers-factory]]
=== The Mappers factory (no dependency injection)
When not using a DI framework, Mapper instances can be retrieved via the `org.mapstruct.factory.Mappers` class. Just invoke the `getMapper()` method, passing the interface type of the mapper to return:
.Using the Mappers factory
====
[source, java, linenums]
[subs="verbatim,attributes"]
----
CarMapper mapper = Mappers.getMapper( CarMapper.class );
----
====
By convention, a mapper interface should define a member called `INSTANCE` which holds a single instance of the mapper type:
.Declaring an instance of a mapper (interface)
====
[source, java, linenums]
[subs="verbatim,attributes"]
----
@Mapper
public interface CarMapper {
CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );
CarDto carToCarDto(Car car);
}
----
====
.Declaring an instance of a mapper (abstract class)
====
[source, java, linenums]
[subs="verbatim,attributes"]
----
@Mapper
public abstract class CarMapper {
public static final CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );
CarDto carToCarDto(Car car);
}
----
====
This pattern makes it very easy for clients to use mapper objects without repeatedly instantiating new instances:
.Accessing a mapper
====
[source, java, linenums]
[subs="verbatim,attributes"]
----
Car car = ...;
CarDto dto = CarMapper.INSTANCE.carToCarDto( car );
----
====
Note that mappers generated by MapStruct are stateless and thread-safe and thus can safely be accessed from several threads at the same time.
[[using-dependency-injection]]
=== Using dependency injection
If you're working with a dependency injection framework such as http://jcp.org/en/jsr/detail?id=346[CDI] (Contexts and Dependency Injection for Java^TM^ EE) or the http://www.springsource.org/spring-framework[Spring Framework], it is recommended to obtain mapper objects via dependency injection and *not* via the `Mappers` class as described above. For that purpose you can specify the component model which generated mapper classes should be based on either via `@Mapper#componentModel` or using a processor option as described in <<configuration-options>>.
Currently there is support for CDI and Spring (the latter either via its custom annotations or using the JSR 330 annotations). See <<configuration-options>> for the allowed values of the `componentModel` attribute which are the same as for the `mapstruct.defaultComponentModel` processor option and constants are defined in a class `MappingConstants.ComponentModel`. In both cases the required annotations will be added to the generated mapper implementations classes in order to make the same subject to dependency injection. The following shows an example using CDI:
.A mapper using the CDI component model
====
[source, java, linenums]
[subs="verbatim,attributes"]
----
@Mapper(componentModel = MappingConstants.ComponentModel.CDI)
public interface CarMapper {
CarDto carToCarDto(Car car);
}
----
====
The generated mapper implementation will be marked with the `@ApplicationScoped` annotation and thus can be injected into fields, constructor arguments etc. using the `@Inject` annotation:
.Obtaining a mapper via dependency injection
====
[source, java, linenums]
[subs="verbatim,attributes"]
----
@Inject
private CarMapper mapper;
----
====
A mapper which uses other mapper classes (see <<invoking-other-mappers>>) will obtain these mappers using the configured component model. So if `CarMapper` from the previous example was using another mapper, this other mapper would have to be an injectable CDI bean as well.
[[injection-strategy]]
=== Injection strategy
When using <<using-dependency-injection,dependency injection>>, you can choose between field and constructor injection.
This can be done by either providing the injection strategy via `@Mapper` or `@MapperConfig` annotation.
.Using constructor injection
====
[source, java, linenums]
[subs="verbatim,attributes"]
----
@Mapper(componentModel = MappingConstants.ComponentModel.CDI, uses = EngineMapper.class, injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface CarMapper {
CarDto carToCarDto(Car car);
}
----
====
The generated mapper will inject all classes defined in the **uses** attribute.
When `InjectionStrategy#CONSTRUCTOR` is used, the constructor will have the appropriate annotation and the fields won't.
When `InjectionStrategy#FIELD` is used, the annotation is on the field itself.
For now, the default injection strategy is field injection, but it can be configured with <<configuration-options>>.
It is recommended to use constructor injection to simplify testing.
[TIP]
====
For abstract classes or decorators setter injection should be used.
====