org.mapstruct.DecoratedWith Maven / Gradle / Ivy
Show all versions of mapstruct Show documentation
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 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 {@code cdi}. Use CDI's own
* {@code @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 {@code 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
* {@code @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 {@code @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'
* Referencing the original mapper
*
* JSR 330 doesn't specify qualifiers and only allows to specifically name the beans. Hence, the generated
* implementation of the original mapper is annotated with
* {@code @javax.inject.Named("fully-qualified-name-of-generated-impl")} and {@code @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 {@code @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
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface DecoratedWith {
/**
* The decorator type. Must be an abstract class that extends or implements the mapper type to which it is applied.
*
* For component-model {@code default}, the decorator type must either have a default constructor or a constructor
* with a single parameter accepting the type of the decorated mapper.
*
* @return the decorator type
*/
Class> value();
}