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
      Class<?> value
      The decorator type.
    • Element Detail

      • 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