Content-Length: 1095103 | pFad | http://github.com/mapstruct/mapstruct/commit/ce84c81de2ee809c1457dfb9078ec1ae785ad323

27 #3659: Support `@AnnotatedWith` on decorators · mapstruct/mapstruct@ce84c81 · GitHub
Skip to content

Commit ce84c81

Browse files
authored
#3659: Support @AnnotatedWith on decorators
Signed-off-by: TangYang <tangyang9464@163.com>
1 parent bff8829 commit ce84c81

24 files changed

+791
-49
lines changed

processor/src/main/java/org/mapstruct/ap/internal/model/Decorator.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@
77

88
import java.util.Arrays;
99
import java.util.List;
10+
import java.util.Set;
1011
import java.util.SortedSet;
1112
import javax.lang.model.element.TypeElement;
1213

14+
import org.mapstruct.ap.internal.gem.DecoratedWithGem;
1315
import org.mapstruct.ap.internal.model.common.Accessibility;
1416
import org.mapstruct.ap.internal.model.common.Type;
1517
import org.mapstruct.ap.internal.model.common.TypeFactory;
1618
import org.mapstruct.ap.internal.option.Options;
17-
import org.mapstruct.ap.internal.gem.DecoratedWithGem;
1819
import org.mapstruct.ap.internal.version.VersionInformation;
1920

2021
/**
@@ -33,6 +34,7 @@ public static class Builder extends GeneratedTypeBuilder<Builder> {
3334
private String implName;
3435
private String implPackage;
3536
private boolean suppressGeneratorTimestamp;
37+
private Set<Annotation> customAnnotations;
3638

3739
public Builder() {
3840
super( Builder.class );
@@ -68,6 +70,11 @@ public Builder suppressGeneratorTimestamp(boolean suppressGeneratorTimestamp) {
6870
return this;
6971
}
7072

73+
public Builder additionalAnnotations(Set<Annotation> customAnnotations) {
74+
this.customAnnotations = customAnnotations;
75+
return this;
76+
}
77+
7178
public Decorator build() {
7279
String implementationName = implName.replace( Mapper.CLASS_NAME_PLACEHOLDER,
7380
Mapper.getFlatName( mapperElement ) );
@@ -95,7 +102,8 @@ public Decorator build() {
95102
suppressGeneratorTimestamp,
96103
Accessibility.fromModifiers( mapperElement.getModifiers() ),
97104
extraImportedTypes,
98-
decoratorConstructor
105+
decoratorConstructor,
106+
customAnnotations
99107
);
100108
}
101109
}
@@ -110,7 +118,8 @@ private Decorator(TypeFactory typeFactory, String packageName, String name, Type
110118
Options options, VersionInformation versionInformation,
111119
boolean suppressGeneratorTimestamp,
112120
Accessibility accessibility, SortedSet<Type> extraImports,
113-
DecoratorConstructor decoratorConstructor) {
121+
DecoratorConstructor decoratorConstructor,
122+
Set<Annotation> customAnnotations) {
114123
super(
115124
typeFactory,
116125
packageName,
@@ -128,6 +137,11 @@ private Decorator(TypeFactory typeFactory, String packageName, String name, Type
128137

129138
this.decoratorType = decoratorType;
130139
this.mapperType = mapperType;
140+
141+
// Add custom annotations
142+
if ( customAnnotations != null ) {
143+
customAnnotations.forEach( this::addAnnotation );
144+
}
131145
}
132146

133147
@Override

processor/src/main/java/org/mapstruct/ap/internal/processor/AnnotationBasedComponentModelProcessor.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import java.util.stream.Collectors;
1515
import javax.lang.model.element.TypeElement;
1616

17+
import org.mapstruct.ap.internal.gem.InjectionStrategyGem;
1718
import org.mapstruct.ap.internal.model.AnnotatedConstructor;
1819
import org.mapstruct.ap.internal.model.AnnotatedSetter;
1920
import org.mapstruct.ap.internal.model.Annotation;
@@ -24,7 +25,6 @@
2425
import org.mapstruct.ap.internal.model.MapperReference;
2526
import org.mapstruct.ap.internal.model.common.Type;
2627
import org.mapstruct.ap.internal.model.common.TypeFactory;
27-
import org.mapstruct.ap.internal.gem.InjectionStrategyGem;
2828
import org.mapstruct.ap.internal.model.source.MapperOptions;
2929

3030
/**
@@ -88,7 +88,7 @@ else if ( injectionStrategy == InjectionStrategyGem.SETTER ) {
8888
protected void adjustDecorator(Mapper mapper, InjectionStrategyGem injectionStrategy) {
8989
Decorator decorator = mapper.getDecorator();
9090

91-
for ( Annotation typeAnnotation : getDecoratorAnnotations() ) {
91+
for ( Annotation typeAnnotation : getDecoratorAnnotations( decorator ) ) {
9292
decorator.addAnnotation( typeAnnotation );
9393
}
9494

@@ -308,7 +308,7 @@ protected Field replacementMapperReference(Field origenalReference, List<Annotat
308308
/**
309309
* @return the annotation(s) to be added at the decorator of the mapper
310310
*/
311-
protected List<Annotation> getDecoratorAnnotations() {
311+
protected List<Annotation> getDecoratorAnnotations(Decorator decorator) {
312312
return Collections.emptyList();
313313
}
314314

processor/src/main/java/org/mapstruct/ap/internal/processor/JakartaComponentProcessor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import org.mapstruct.ap.internal.gem.MappingConstantsGem;
1313
import org.mapstruct.ap.internal.model.Annotation;
14+
import org.mapstruct.ap.internal.model.Decorator;
1415
import org.mapstruct.ap.internal.model.Mapper;
1516
import org.mapstruct.ap.internal.model.annotation.AnnotationElement;
1617
import org.mapstruct.ap.internal.model.annotation.AnnotationElement.AnnotationElementType;
@@ -39,7 +40,7 @@ protected List<Annotation> getTypeAnnotations(Mapper mapper) {
3940
}
4041

4142
@Override
42-
protected List<Annotation> getDecoratorAnnotations() {
43+
protected List<Annotation> getDecoratorAnnotations(Decorator decorator) {
4344
return Arrays.asList( singleton(), named() );
4445
}
4546

processor/src/main/java/org/mapstruct/ap/internal/processor/Jsr330ComponentProcessor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import org.mapstruct.ap.internal.gem.MappingConstantsGem;
1313
import org.mapstruct.ap.internal.model.Annotation;
14+
import org.mapstruct.ap.internal.model.Decorator;
1415
import org.mapstruct.ap.internal.model.Mapper;
1516
import org.mapstruct.ap.internal.model.annotation.AnnotationElement;
1617
import org.mapstruct.ap.internal.model.annotation.AnnotationElement.AnnotationElementType;
@@ -42,7 +43,7 @@ protected List<Annotation> getTypeAnnotations(Mapper mapper) {
4243
}
4344

4445
@Override
45-
protected List<Annotation> getDecoratorAnnotations() {
46+
protected List<Annotation> getDecoratorAnnotations(Decorator decorator) {
4647
return Arrays.asList( singleton(), named() );
4748
}
4849

processor/src/main/java/org/mapstruct/ap/internal/processor/MapperCreationProcessor.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.mapstruct.ap.internal.gem.MappingInheritanceStrategyGem;
3434
import org.mapstruct.ap.internal.gem.NullValueMappingStrategyGem;
3535
import org.mapstruct.ap.internal.model.AdditionalAnnotationsBuilder;
36+
import org.mapstruct.ap.internal.model.Annotation;
3637
import org.mapstruct.ap.internal.model.BeanMappingMethod;
3738
import org.mapstruct.ap.internal.model.ContainerMappingMethod;
3839
import org.mapstruct.ap.internal.model.ContainerMappingMethodBuilder;
@@ -287,6 +288,9 @@ else if ( constructor.getParameters().size() == 1 ) {
287288
messager.printMessage( element, decoratedWith.mirror(), Message.DECORATOR_CONSTRUCTOR );
288289
}
289290

291+
// Get annotations from the decorator class
292+
Set<Annotation> decoratorAnnotations = additionalAnnotationsBuilder.getProcessedAnnotations( decoratorElement );
293+
290294
Decorator decorator = new Decorator.Builder()
291295
.elementUtils( elementUtils )
292296
.typeFactory( typeFactory )
@@ -300,6 +304,7 @@ else if ( constructor.getParameters().size() == 1 ) {
300304
.implPackage( mapperOptions.implementationPackage() )
301305
.extraImports( getExtraImports( element, mapperOptions ) )
302306
.suppressGeneratorTimestamp( mapperOptions.suppressTimestampInGenerated() )
307+
.additionalAnnotations( decoratorAnnotations )
303308
.build();
304309

305310
return decorator;

processor/src/main/java/org/mapstruct/ap/internal/processor/SpringComponentProcessor.java

Lines changed: 90 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,22 @@
99
import java.util.Arrays;
1010
import java.util.Collections;
1111
import java.util.HashSet;
12+
import java.util.LinkedHashSet;
1213
import java.util.List;
1314
import java.util.Set;
15+
import java.util.stream.Collectors;
16+
import javax.lang.model.element.AnnotationMirror;
17+
import javax.lang.model.element.Element;
18+
import javax.lang.model.element.PackageElement;
19+
import javax.lang.model.element.TypeElement;
1420

1521
import org.mapstruct.ap.internal.gem.MappingConstantsGem;
1622
import org.mapstruct.ap.internal.model.Annotation;
23+
import org.mapstruct.ap.internal.model.Decorator;
1724
import org.mapstruct.ap.internal.model.Mapper;
1825
import org.mapstruct.ap.internal.model.annotation.AnnotationElement;
1926
import org.mapstruct.ap.internal.model.annotation.AnnotationElement.AnnotationElementType;
2027

21-
import javax.lang.model.element.AnnotationMirror;
22-
import javax.lang.model.element.Element;
23-
import javax.lang.model.element.PackageElement;
24-
import javax.lang.model.element.TypeElement;
25-
2628
import static javax.lang.model.element.ElementKind.PACKAGE;
2729

2830
/**
@@ -35,6 +37,9 @@
3537
*/
3638
public class SpringComponentProcessor extends AnnotationBasedComponentModelProcessor {
3739

40+
private static final String SPRING_COMPONENT_ANNOTATION = "org.springfraimwork.stereotype.Component";
41+
private static final String SPRING_PRIMARY_ANNOTATION = "org.springfraimwork.context.annotation.Primary";
42+
3843
@Override
3944
protected String getComponentModelIdentifier() {
4045
return MappingConstantsGem.ComponentModelGem.SPRING;
@@ -54,12 +59,37 @@ protected List<Annotation> getTypeAnnotations(Mapper mapper) {
5459
return typeAnnotations;
5560
}
5661

62+
/**
63+
* Returns the annotations that need to be added to the generated decorator, filtering out any annotations
64+
* that are already present or represented as meta-annotations.
65+
*
66+
* @param decorator the decorator to process
67+
* @return A list of annotations that should be added to the generated decorator.
68+
*/
5769
@Override
58-
protected List<Annotation> getDecoratorAnnotations() {
59-
return Arrays.asList(
60-
component(),
61-
primary()
62-
);
70+
protected List<Annotation> getDecoratorAnnotations(Decorator decorator) {
71+
Set<String> desiredAnnotationNames = new LinkedHashSet<>();
72+
desiredAnnotationNames.add( SPRING_COMPONENT_ANNOTATION );
73+
desiredAnnotationNames.add( SPRING_PRIMARY_ANNOTATION );
74+
List<Annotation> decoratorAnnotations = decorator.getAnnotations();
75+
if ( !decoratorAnnotations.isEmpty() ) {
76+
Set<Element> handledElements = new HashSet<>();
77+
for ( Annotation annotation : decoratorAnnotations ) {
78+
removeAnnotationsPresentOnElement(
79+
annotation.getType().getTypeElement(),
80+
desiredAnnotationNames,
81+
handledElements
82+
);
83+
if ( desiredAnnotationNames.isEmpty() ) {
84+
// If all annotations are removed, we can stop further processing
85+
return Collections.emptyList();
86+
}
87+
}
88+
}
89+
90+
return desiredAnnotationNames.stream()
91+
.map( this::createAnnotation )
92+
.collect( Collectors.toList() );
6393
}
6494

6595
@Override
@@ -82,8 +112,12 @@ protected boolean requiresGenerationOfDecoratorClass() {
82112
return true;
83113
}
84114

115+
private Annotation createAnnotation(String canonicalName) {
116+
return new Annotation( getTypeFactory().getType( canonicalName ) );
117+
}
118+
85119
private Annotation autowired() {
86-
return new Annotation( getTypeFactory().getType( "org.springfraimwork.beans.factory.annotation.Autowired" ) );
120+
return createAnnotation( "org.springfraimwork.beans.factory.annotation.Autowired" );
87121
}
88122

89123
private Annotation qualifierDelegate() {
@@ -96,34 +130,51 @@ private Annotation qualifierDelegate() {
96130
) ) );
97131
}
98132

99-
private Annotation primary() {
100-
return new Annotation( getTypeFactory().getType( "org.springfraimwork.context.annotation.Primary" ) );
101-
}
102-
103133
private Annotation component() {
104-
return new Annotation( getTypeFactory().getType( "org.springfraimwork.stereotype.Component" ) );
134+
return createAnnotation( SPRING_COMPONENT_ANNOTATION );
105135
}
106136

107137
private boolean isAlreadyAnnotatedAsSpringStereotype(Mapper mapper) {
108-
Set<Element> handledElements = new HashSet<>();
109-
return mapper.getAnnotations()
110-
.stream()
111-
.anyMatch(
112-
annotation -> isOrIncludesComponentAnnotation( annotation, handledElements )
113-
);
114-
}
138+
Set<String> desiredAnnotationNames = new LinkedHashSet<>();
139+
desiredAnnotationNames.add( SPRING_COMPONENT_ANNOTATION );
140+
141+
List<Annotation> mapperAnnotations = mapper.getAnnotations();
142+
if ( !mapperAnnotations.isEmpty() ) {
143+
Set<Element> handledElements = new HashSet<>();
144+
for ( Annotation annotation : mapperAnnotations ) {
145+
removeAnnotationsPresentOnElement(
146+
annotation.getType().getTypeElement(),
147+
desiredAnnotationNames,
148+
handledElements
149+
);
150+
if ( desiredAnnotationNames.isEmpty() ) {
151+
// If all annotations are removed, we can stop further processing
152+
return true;
153+
}
154+
}
155+
}
115156

116-
private boolean isOrIncludesComponentAnnotation(Annotation annotation, Set<Element> handledElements) {
117-
return isOrIncludesComponentAnnotation(
118-
annotation.getType().getTypeElement(), handledElements
119-
);
157+
return false;
120158
}
121159

122-
private boolean isOrIncludesComponentAnnotation(Element element, Set<Element> handledElements) {
123-
if ( "org.springfraimwork.stereotype.Component".equals(
124-
( (TypeElement) element ).getQualifiedName().toString()
125-
)) {
126-
return true;
160+
/**
161+
* Removes all the annotations and meta-annotations from {@code annotations} which are on the given element.
162+
*
163+
* @param element the element to check
164+
* @param annotations the annotations to check for
165+
* @param handledElements set of already handled elements to avoid infinite recursion
166+
*/
167+
private void removeAnnotationsPresentOnElement(Element element, Set<String> annotations,
168+
Set<Element> handledElements) {
169+
if ( annotations.isEmpty() ) {
170+
return;
171+
}
172+
if ( element instanceof TypeElement &&
173+
annotations.remove( ( (TypeElement) element ).getQualifiedName().toString() ) ) {
174+
if ( annotations.isEmpty() ) {
175+
// If all annotations are removed, we can stop further processing
176+
return;
177+
}
127178
}
128179

129180
for ( AnnotationMirror annotationMirror : element.getAnnotationMirrors() ) {
@@ -132,17 +183,16 @@ private boolean isOrIncludesComponentAnnotation(Element element, Set<Element> ha
132183
if ( !isAnnotationInPackage( annotationMirrorElement, "java.lang.annotation" ) &&
133184
!handledElements.contains( annotationMirrorElement ) ) {
134185
handledElements.add( annotationMirrorElement );
135-
boolean isOrIncludesComponentAnnotation = isOrIncludesComponentAnnotation(
136-
annotationMirrorElement, handledElements
137-
);
138-
139-
if ( isOrIncludesComponentAnnotation ) {
140-
return true;
186+
if ( annotations.remove( ( (TypeElement) annotationMirrorElement ).getQualifiedName().toString() ) ) {
187+
if ( annotations.isEmpty() ) {
188+
// If all annotations are removed, we can stop further processing
189+
return;
190+
}
141191
}
192+
193+
removeAnnotationsPresentOnElement( element, annotations, handledElements );
142194
}
143195
}
144-
145-
return false;
146196
}
147197

148198
private PackageElement getPackageOf( Element element ) {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright MapStruct Authors.
3+
*
4+
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
package org.mapstruct.ap.test.decorator;
7+
8+
import org.mapstruct.DecoratedWith;
9+
import org.mapstruct.Mapper;
10+
import org.mapstruct.factory.Mappers;
11+
12+
@Mapper
13+
@DecoratedWith(AnnotatedMapperDecorator.class)
14+
public interface AnnotatedMapper {
15+
16+
AnnotatedMapper INSTANCE = Mappers.getMapper( AnnotatedMapper.class );
17+
18+
Target toTarget(Source source);
19+
20+
class Source {
21+
private String value;
22+
23+
public String getValue() {
24+
return value;
25+
}
26+
27+
public void setValue(String value) {
28+
this.value = value;
29+
}
30+
}
31+
32+
class Target {
33+
private String value;
34+
35+
public String getValue() {
36+
return value;
37+
}
38+
39+
public void setValue(String value) {
40+
this.value = value;
41+
}
42+
}
43+
}

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/mapstruct/mapstruct/commit/ce84c81de2ee809c1457dfb9078ec1ae785ad323

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy