I will summarize how to use MapStruct.
The version to use is 1.2.0.Final
.
Mapper class is created by adding @Mapper
to interface class or abstract class.
@Mapper
public interface FooMapper {
// omit..
}
@Mapper
public abstract FooMapper {
// omit..
}
After creating the Mapper class, define the Mapping method.
Use @Mapping
to specify the field name to be mapped to the target attribute and the field name to be mapped to the source attribute.
It can be omitted if the field names are the same.
@Mapper
public interface FooMapper {
@Mapping(target="name", source="firstName")
Bar fooToBar(Foo foo);
}
An instance of the Mapper class can be created with Mappers # getMapper
.
Mappers.getMapper(FooMapper.class);
You can change the instance creation method by specifying the componentModel attribute of @ Mapper
.
This time, we will enable DI with Spring Framework.
//Specify spring
@Mapper(componentModel = "spring")
public interface FooMapper {
// omit..
}
If you look at the automatically generated Mapper class, you can see that @Component
is added.
import org.springframework.stereotype.Component;
@Component
public class FooMapperImpl implements FooMapper {
// omit..
}
See official documentation for other methods http://mapstruct.org/documentation/stable/reference/html/#retrieving-mapper
MapStruct provides several ways to customize the mapping process.
Use the constant attribute of @Mapping
.
@Mapper
public interface FooMapper {
@Mapping(target="name", constant = "Hogehoge")
Bar fooToBar(Foo foo);
}
You can set the default value in the defaultValue attribute of @Mapping
.
Applies when the value to be mapped is null.
@Mapper
public interface FooMapper {
@Mapping(target="name", defaultValue = "Hogehoge")
Bar fooToBar(Foo foo);
}
Arbitrary Java code can be specified for the mapping process in the Expression attribute of @Mapping
.
Enclose the Java code in java ()
.
@Mapper
public interface FooMapper {
@Mapping(target="now", expression = "java(java.time.LocalDate.now())")
Bar fooToBar(Foo foo);
}
If you use the imports attribute of @ Mapper
, you do not have to describe from the package name.
@Mapper(imports = LocalDate.class)
public interface FooMapper {
@Mapping(target="now", expression = "java(LocalDate.now())")
Bar fooToBar(Foo foo);
}
You can specify the format of the number in the numberFormat attribute of @Mapping
.
@Mapper
public interface FooMapper {
@Mapping(target="num", numberFormat = "000") //Zero padding
Bar fooToBar(Foo foo);
}
You can specify the date format in the dateFormat attribute of @Mapping
.
@Mapper
public interface FooMapper {
@Mapping(target="date", dateFormat = "yyyy/MM/dd")
Bar fooToBar(Foo foo);
}
You can map different Enums.
Use @ValueMapping
to map Enums.
@Mapper
public interface FooMapper {
@ValueMapping(source = "SMALL", target = "SHORT")
@ValueMapping(source = "MEDIUM", target = "TALL")
@ValueMapping(source = "LARGE", target = "GRANDE")
BarEnum fooToBar(FooEnum foo);
}
If there is no target to be mapped, set null by specifying MappingConstants.NULL
in the staget attribute.
@ValueMapping(source = "VENTI", target = MappingConstants.NULL)
If you want to specify the default value, specify MappingConstants.ANY_REMAINING
in the source attribute.
@ValueMapping(source = MappingConstants.ANY_REMAINING, target = "LARGE")
@ Qualifier
It can be used when you want to add special behavior. As an example, add a process to convert to uppercase.
Create two annotations that combine @ Qualifier
, one for class level and one for method level.
For class level
@Qualifier
@Retention(CLASS)
@Target(TYPE)
public @interface Converter {
}
For method level
@Qualifier
@Retention(CLASS)
@Target(METHOD)
public @interface ToUpper {
}
Create a class that defines the behavior. At this time, add the annotation created above.
@Converter
public class StringConverter {
@ToUpper
public String upperCase(String string) {
return (string == null) ? null : string.toUpperCase();
}
}
Specify the class that defines the behavior in the uses attribute of @ Mapper
.
Specify two annotation classes in the qualifiedBy attribute of @Mapping
and add the behavior to the mapping.
@Mapper(uses = StringConverter.class)
public interface FooMapper {
@Mapping(target="name", qualifiedBy = { Converter.class, ToUpper.class })
Bar fooToBar(Foo foo);
}
@Context
The behavior of mapping can be changed from the outside by using @Context
.
Add an argument with @Context
added to the argument of the mapping method.
@Mapper
public interface FooMapper {
Bar fooToBar(Foo foo, @Context Locale locale);
}
Define a custom method with arguments with @Context
.
In the example below, a field of type LocalDate will be formatted and mapped to the specified Local.
@Mapper
public interface FooMapper {
Bar fooToBar(Foo foo, @Context Locale locale);
default String format(LocalDate date, @Context Locale locale) {
//Format according to Local, etc.
}
}
Decorators allow you to override the mapping process and add special processing.
First, create a Mapper class.
@Mapper
public interface FooMapper {
Bar fooToBar(Foo foo);
}
The Decorator class is an abstract class and is a subtype of Mapper to customize.
public abstract class FooMapperDecorator implements FooMapper {
private final FooMapper delegate;
public FooMapperDecorator(FooMapper delegate) {
this.delegate = delegate;
}
//Override the method you want to customize
@Override
public Bar fooToBar(Foo foo) {
Bar bar = delegate.fooToBar(foo);
//Add special processing
return bar;
}
}
Apply the Decorator class to the Mapper class.
To apply, use @DecoratedWith
.
@Mapper
@DecoratedWith(FooMapperDecorator.class)
public interface FooMapper {
Bar fooToBar(Foo foo);
}
By using @BeforeMapping
and @AfterMapping
, you can execute your own processing before and after the mapping process.
@Mapper
public abstract class FooMapper {
//The method you want to execute before mapping
@BeforeMapping
protected void before(Foo foo) {
// omit..
}
//The method you want to execute after mapping
@AfterMapping
protected void after(@MappingTarget Bar bar) {
// omit..
}
public abstract Bar fooToBar(Foo foo);
}
Generated Mapper
public class FooMapperImpl extends FooMapper {
@Override
public Bar fooToBar(Foo foo) {
//Run before mapping
before( foo );
if ( foo == null ) {
return null;
}
//Mapping process
//Run after mapping
after( bar );
return bar;
}
}
Once defined, the mapping can be reused by using @InheritConfiguration
.
@Mapper(config = FooConfig.class)
public interface FooMapper {
@Mapping(...)
Bar fooToBar(Foo foo);
@InheritConfiguration
Bar fuga(Foo foo);
}
You can reuse it as a reverse mapping by using @InheritInverseConfiguration
.
@Mapper(config = FooConfig.class)
public interface FooMapper {
@Mapping(...)
Bar fooToBar(Foo foo);
@InheritInverseConfiguration
Foo barToFoo(Bar bar);
}
You can create a configuration class with @MappingConfig
.
In the setting class, you can specify the component model and set whether to issue a warning or error when there is an item that is not mapped.
See Javadoc for details.
http://mapstruct.org/documentation/stable/api/org/mapstruct/MapperConfig.html
@MapperConfig(unmappedTargetPolicy = ReportingPolicy.IGNORE
, mappingInheritanceStrategy = MappingInheritanceStrategy.AUTO_INHERIT_ALL_FROM_CONFIG)
public interface FooConfig {
}
Set the created class to the Mapper class.
Specify the created setting class in the config attribute of @Mapper
.
@Mapper(config = FooConfig.class)
public interface FooMapper {
// omit..
}
Recommended Posts