[JAVA] How to use MapStruct

I will summarize how to use MapStruct. The version to use is 1.2.0.Final.

Creating a Mapper class

Mapper class is created by adding @Mapper to interface class or abstract class.

@Mapper
public interface FooMapper {
    // omit..
}

@Mapper
public abstract FooMapper {
    // omit..
}

Mapping method definition

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);
}

Instance of Mapper class

An instance of the Mapper class can be created with Mappers # getMapper.

Mappers.getMapper(FooMapper.class);

Specifying the component model

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

Customize the mapping process

MapStruct provides several ways to customize the mapping process.

Map constants

Use the constant attribute of @Mapping.

@Mapper
public interface FooMapper {
    @Mapping(target="name", constant = "Hogehoge")
    Bar fooToBar(Foo foo);
}

Set the default value

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);
}

Execute arbitrary Java code

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);
}

Format the number

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);
}

Format the date

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);
}

Mapping between different Enums

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")

Use @ Qualifier

It can be used when you want to add special behavior. As an example, add a process to convert to uppercase.

Creating annotations

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 {
}

Definition of behavior

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();
    }
}

Creating a Mapper

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);
}

Use @Context

The behavior of mapping can be changed from the outside by using @Context.

Creating a Mapper

Add an argument with @Context added to the argument of the mapping method.

@Mapper
public interface FooMapper {
    Bar fooToBar(Foo foo, @Context Locale locale);
}

Add custom method

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.
    }
}

Use Decorator

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);
}

Creating a Decorator class

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 Decorator

Apply the Decorator class to the Mapper class. To apply, use @DecoratedWith.

@Mapper
@DecoratedWith(FooMapperDecorator.class)
public interface FooMapper {
    Bar fooToBar(Foo foo);
}

Add your own processing before and after the mapping process

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;
    }
}

Reuse of mapping

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);
}

Configuration class

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

How to use MapStruct
How to use rbenv
How to use letter_opener_web
How to use with_option
How to use java.util.logging
How to use map
How to use Twitter4J
How to use active_hash! !!
How to use hidden_field_tag
How to use TreeSet
[How to use label]
How to use identity
How to use hashes
How to use JUnit 5
How to use Dozer.mapper
How to use Gradle
How to use org.immutables
How to use java.util.stream.Collector
How to use VisualVM
How to use Map
[Java] How to use Map
How to use Chain API
[Java] How to use Map
How to use Priority Queuing
[Rails] How to use enum
How to use java Optional
How to use JUnit (beginner)
How to use Ruby return
[Rails] How to use enum
How to use @Builder (Lombok)
[Swift] How to use UserDefaults
How to use java class
How to use Swift UIScrollView
How to use Big Decimal
[Java] How to use Optional ②
[Java] How to use removeAll ()
How to use String [] args
[Java] How to use string.format
How to use rails join
How to use Java Map
Ruby: How to use cookies
How to use dependent :: destroy
How to use Eclipse Debug_Shell
How to use Apache POI
[Rails] How to use validation
How to use Java variables
[Rails] How to use authenticate_user!
[Rails] How to use "kaminari"
How to use GC Viewer
[Java] How to use Optional ①
How to use Lombok now
[Creating] How to use JUnit
[Rails] How to use Scope
How to use the link_to method
[Rails] How to use gem "devise"
How to use Lombok in Spring
How to use StringBurrer and Arrays.toString.
How to use arrays (personal memorandum)
How to use Java HttpClient (Get)
How to use the include? method
How to use the form_with method