forked from mapstruct/mapstruct
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDecoratedWith.java
More file actions
160 lines (157 loc) · 6.03 KB
/
DecoratedWith.java
File metadata and controls
160 lines (157 loc) · 6.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
* 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.
* <p>
* 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.
* <p>
* <b>NOTE:</b> The usage of decorated mappers differs depending on the selected component model.
* <p>
* <b>NOTE:</b> This annotation is not supported for the component model {@code cdi}. Use CDI's own
* <a href="https://docs.jboss.org/cdi/spec/1.0/html/decorators.html">{@code @Decorator}</a> feature instead.
* </p>
* <h2>Examples</h2>
* <p>
* For the examples below, consider the following mapper declaration:
*
* <pre>
* @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
* }
* </pre>
*
* <h3>1. Component model 'default'</h3>
* <h4>Referencing the original mapper in the decorator</h4>
* <p>
* 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:
*
* <pre>
* 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;
* }
* }
* </pre>
*
* <h4>Using the decorated mapper</h4>
* <p>
* Nothing special needs to be done. When using {@code Mappers.getMapper( PersonMapper.class )}, the <em>decorator</em>
* is returned, with the injected original mapper.
* <h3>2. Component model 'spring'</h3>
* <h4>Referencing the original mapper in the decorator</h4>
* <p>
* 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:
*
* <pre>
* 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;
* }
* }
* </pre>
*
* <h4>Using the decorated mapper in the decorator</h4>
* <p>
* 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:
*
* <pre>
* @Autowired
* private PersonMapper personMapper; // injects the decorator, with the injected original mapper
* </pre>
*
* <h3>3. Component model 'jsr330' or 'jakarta'</h3>
* <h4>Referencing the original mapper</h4>
* <p>
* 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
* {@code @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):
*
* <pre>
* 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;
* }
* }
* </pre>
*
* <h4>Using the decorated mapper in the decorator</h4>
* <p>
* 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
* <em>decorator</em> to be injected:
*
* <pre>
* @Inject
* @javax.inject.Named
* private PersonMapper personMapper; // injects the decorator, with the injected original mapper
* </pre>
* <p>
*
* @author Gunnar Morling
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface DecoratedWith {
/**
* The decorator type. Must be an abstract class that extends or implements the mapper type to which it is applied.
* <p>
* 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();
}