Package org.mapstruct

Annotation Type DecoratedWith


@Target(TYPE) @Retention(CLASS) public @interface DecoratedWith
Specifies a decorator to be applied to a generated mapper, which e.g. can be used to amend mappings performed by generated mapping methods.

A typical decorator implementation will be an abstract class and only implement/override a subset of the methods of the mapper type which it decorates. All methods not implemented or overridden by the decorator will be implemented by the code generator by delegating to the generated mapper implementation.

NOTE: The usage of decorated mappers differs depending on the selected component model.

NOTE: This annotation is not supported for the component model cdi. Use CDI's own @Decorator feature instead.

Examples

For the examples below, consider the following mapper declaration:

 @Mapper(componentModel = "...")
 @DecoratedWith(PersonMapperDecorator.class)
 public interface PersonMapper {

     @Mapping(target = "name", ignore = true)
     PersonDto personToPersonDto(Person person);

     AddressDto addressToAddressDto(Address address); // not touched by the decorator
 }
 

1. Component model 'default'

Referencing the original mapper in the decorator

If a constructor with a single parameter accepting the type of the decorated mapper is present, a delegate with generated implementations of all the mapper methods will be passed to this constructor. A typical implementation will store the passed delegate in a field of the decorator and make use of it in the decorator methods:

 public abstract class PersonMapperDecorator implements PersonMapper {

     private PersonMapper delegate;

     public PersonMapperDecorator(PersonMapper delegate) {
         this.delegate = delegate;
     }

     @Override
     public PersonDto personToPersonDto(Person person) {
         PersonDto dto = delegate.personToPersonDto( person );
         dto.setName( person.getFirstName() + " " + person.getLastName() );

         return dto;
     }
 }
 

Using the decorated mapper

Nothing special needs to be done. When using Mappers.getMapper( PersonMapper.class ), the decorator is returned, with the injected original mapper.

2. Component model 'spring'

Referencing the original mapper in the decorator

The generated implementation of the original mapper is annotated with the Spring annotation @org.springframework.beans.factory.annotation.Qualifier("delegate"). To autowire that bean in your decorator, add that qualifier annotation as well:

 public abstract class PersonMapperDecorator implements PersonMapper {

     @Autowired
     @org.springframework.beans.factory.annotation.Qualifier("delegate")
     private PersonMapper delegate;

     @Override
     public PersonDto personToPersonDto(Person person) {
         PersonDto dto = delegate.personToPersonDto( person );
         dto.setName( person.getFirstName() + " " + person.getLastName() );

         return dto;
     }
 }
 

Using the decorated mapper in the decorator

The generated class that extends the decorator is annotated with Spring's @Primary annotation. To autowire the decorated mapper in the application, nothing special needs to be done:

 @Autowired
 private PersonMapper personMapper; // injects the decorator, with the injected original mapper
 

3. Component model 'jsr330' or 'jakarta'

Referencing the original mapper

JSR 330 / Jakarta Inject doesn't specify qualifiers and only allows to specifically name the beans. Hence, the generated implementation of the original mapper is annotated with @Named("fully-qualified-name-of-generated-impl") and @Singleton (please note that when using a decorator, the class name of the mapper implementation ends with an underscore). To inject that bean in your decorator, add the same annotation to the delegate field (e.g. by copy/pasting it from the generated class):

 public abstract class PersonMapperDecorator implements PersonMapper {

     @Inject
     @javax.inject.Named("org.examples.PersonMapperImpl_")
     private PersonMapper delegate;

     @Override
     public PersonDto personToPersonDto(Person person) {
         PersonDto dto = delegate.personToPersonDto( person );
         dto.setName( person.getFirstName() + " " + person.getLastName() );

         return dto;
     }
 }
 

Using the decorated mapper in the decorator

Unlike with the other component models, the usage site must be aware if a mapper is decorated or not, as for decorated mappers, the parameterless @javax.inject.Named annotation must be added to select the decorator to be injected:

 @Inject
 @javax.inject.Named
 private PersonMapper personMapper; // injects the decorator, with the injected original mapper
 
Author:
Gunnar Morling
  • Required Element Summary

    Required Elements
    Modifier and Type
    Required Element
    Description
    The decorator type.
  • Element Details

    • value

      Class<?> value
      The decorator type. Must be an abstract class that extends or implements the mapper type to which it is applied.

      For component-model default, the decorator type must either have a default constructor or a constructor with a single parameter accepting the type of the decorated mapper.

      Returns:
      the decorator type