mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#3659: Support @AnnotatedWith
on decorators
Signed-off-by: TangYang <tangyang9464@163.com>
This commit is contained in:
parent
bff88297e3
commit
ce84c81de2
@ -7,14 +7,15 @@ package org.mapstruct.ap.internal.model;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.internal.gem.DecoratedWithGem;
|
||||||
import org.mapstruct.ap.internal.model.common.Accessibility;
|
import org.mapstruct.ap.internal.model.common.Accessibility;
|
||||||
import org.mapstruct.ap.internal.model.common.Type;
|
import org.mapstruct.ap.internal.model.common.Type;
|
||||||
import org.mapstruct.ap.internal.model.common.TypeFactory;
|
import org.mapstruct.ap.internal.model.common.TypeFactory;
|
||||||
import org.mapstruct.ap.internal.option.Options;
|
import org.mapstruct.ap.internal.option.Options;
|
||||||
import org.mapstruct.ap.internal.gem.DecoratedWithGem;
|
|
||||||
import org.mapstruct.ap.internal.version.VersionInformation;
|
import org.mapstruct.ap.internal.version.VersionInformation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,6 +34,7 @@ public class Decorator extends GeneratedType {
|
|||||||
private String implName;
|
private String implName;
|
||||||
private String implPackage;
|
private String implPackage;
|
||||||
private boolean suppressGeneratorTimestamp;
|
private boolean suppressGeneratorTimestamp;
|
||||||
|
private Set<Annotation> customAnnotations;
|
||||||
|
|
||||||
public Builder() {
|
public Builder() {
|
||||||
super( Builder.class );
|
super( Builder.class );
|
||||||
@ -68,6 +70,11 @@ public class Decorator extends GeneratedType {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder additionalAnnotations(Set<Annotation> customAnnotations) {
|
||||||
|
this.customAnnotations = customAnnotations;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Decorator build() {
|
public Decorator build() {
|
||||||
String implementationName = implName.replace( Mapper.CLASS_NAME_PLACEHOLDER,
|
String implementationName = implName.replace( Mapper.CLASS_NAME_PLACEHOLDER,
|
||||||
Mapper.getFlatName( mapperElement ) );
|
Mapper.getFlatName( mapperElement ) );
|
||||||
@ -95,7 +102,8 @@ public class Decorator extends GeneratedType {
|
|||||||
suppressGeneratorTimestamp,
|
suppressGeneratorTimestamp,
|
||||||
Accessibility.fromModifiers( mapperElement.getModifiers() ),
|
Accessibility.fromModifiers( mapperElement.getModifiers() ),
|
||||||
extraImportedTypes,
|
extraImportedTypes,
|
||||||
decoratorConstructor
|
decoratorConstructor,
|
||||||
|
customAnnotations
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,7 +118,8 @@ public class Decorator extends GeneratedType {
|
|||||||
Options options, VersionInformation versionInformation,
|
Options options, VersionInformation versionInformation,
|
||||||
boolean suppressGeneratorTimestamp,
|
boolean suppressGeneratorTimestamp,
|
||||||
Accessibility accessibility, SortedSet<Type> extraImports,
|
Accessibility accessibility, SortedSet<Type> extraImports,
|
||||||
DecoratorConstructor decoratorConstructor) {
|
DecoratorConstructor decoratorConstructor,
|
||||||
|
Set<Annotation> customAnnotations) {
|
||||||
super(
|
super(
|
||||||
typeFactory,
|
typeFactory,
|
||||||
packageName,
|
packageName,
|
||||||
@ -128,6 +137,11 @@ public class Decorator extends GeneratedType {
|
|||||||
|
|
||||||
this.decoratorType = decoratorType;
|
this.decoratorType = decoratorType;
|
||||||
this.mapperType = mapperType;
|
this.mapperType = mapperType;
|
||||||
|
|
||||||
|
// Add custom annotations
|
||||||
|
if ( customAnnotations != null ) {
|
||||||
|
customAnnotations.forEach( this::addAnnotation );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -14,6 +14,7 @@ import java.util.Set;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.internal.gem.InjectionStrategyGem;
|
||||||
import org.mapstruct.ap.internal.model.AnnotatedConstructor;
|
import org.mapstruct.ap.internal.model.AnnotatedConstructor;
|
||||||
import org.mapstruct.ap.internal.model.AnnotatedSetter;
|
import org.mapstruct.ap.internal.model.AnnotatedSetter;
|
||||||
import org.mapstruct.ap.internal.model.Annotation;
|
import org.mapstruct.ap.internal.model.Annotation;
|
||||||
@ -24,7 +25,6 @@ import org.mapstruct.ap.internal.model.Mapper;
|
|||||||
import org.mapstruct.ap.internal.model.MapperReference;
|
import org.mapstruct.ap.internal.model.MapperReference;
|
||||||
import org.mapstruct.ap.internal.model.common.Type;
|
import org.mapstruct.ap.internal.model.common.Type;
|
||||||
import org.mapstruct.ap.internal.model.common.TypeFactory;
|
import org.mapstruct.ap.internal.model.common.TypeFactory;
|
||||||
import org.mapstruct.ap.internal.gem.InjectionStrategyGem;
|
|
||||||
import org.mapstruct.ap.internal.model.source.MapperOptions;
|
import org.mapstruct.ap.internal.model.source.MapperOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,7 +88,7 @@ public abstract class AnnotationBasedComponentModelProcessor implements ModelEle
|
|||||||
protected void adjustDecorator(Mapper mapper, InjectionStrategyGem injectionStrategy) {
|
protected void adjustDecorator(Mapper mapper, InjectionStrategyGem injectionStrategy) {
|
||||||
Decorator decorator = mapper.getDecorator();
|
Decorator decorator = mapper.getDecorator();
|
||||||
|
|
||||||
for ( Annotation typeAnnotation : getDecoratorAnnotations() ) {
|
for ( Annotation typeAnnotation : getDecoratorAnnotations( decorator ) ) {
|
||||||
decorator.addAnnotation( typeAnnotation );
|
decorator.addAnnotation( typeAnnotation );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,7 +308,7 @@ public abstract class AnnotationBasedComponentModelProcessor implements ModelEle
|
|||||||
/**
|
/**
|
||||||
* @return the annotation(s) to be added at the decorator of the mapper
|
* @return the annotation(s) to be added at the decorator of the mapper
|
||||||
*/
|
*/
|
||||||
protected List<Annotation> getDecoratorAnnotations() {
|
protected List<Annotation> getDecoratorAnnotations(Decorator decorator) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.mapstruct.ap.internal.gem.MappingConstantsGem;
|
import org.mapstruct.ap.internal.gem.MappingConstantsGem;
|
||||||
import org.mapstruct.ap.internal.model.Annotation;
|
import org.mapstruct.ap.internal.model.Annotation;
|
||||||
|
import org.mapstruct.ap.internal.model.Decorator;
|
||||||
import org.mapstruct.ap.internal.model.Mapper;
|
import org.mapstruct.ap.internal.model.Mapper;
|
||||||
import org.mapstruct.ap.internal.model.annotation.AnnotationElement;
|
import org.mapstruct.ap.internal.model.annotation.AnnotationElement;
|
||||||
import org.mapstruct.ap.internal.model.annotation.AnnotationElement.AnnotationElementType;
|
import org.mapstruct.ap.internal.model.annotation.AnnotationElement.AnnotationElementType;
|
||||||
@ -39,7 +40,7 @@ public class JakartaComponentProcessor extends AnnotationBasedComponentModelProc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<Annotation> getDecoratorAnnotations() {
|
protected List<Annotation> getDecoratorAnnotations(Decorator decorator) {
|
||||||
return Arrays.asList( singleton(), named() );
|
return Arrays.asList( singleton(), named() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.mapstruct.ap.internal.gem.MappingConstantsGem;
|
import org.mapstruct.ap.internal.gem.MappingConstantsGem;
|
||||||
import org.mapstruct.ap.internal.model.Annotation;
|
import org.mapstruct.ap.internal.model.Annotation;
|
||||||
|
import org.mapstruct.ap.internal.model.Decorator;
|
||||||
import org.mapstruct.ap.internal.model.Mapper;
|
import org.mapstruct.ap.internal.model.Mapper;
|
||||||
import org.mapstruct.ap.internal.model.annotation.AnnotationElement;
|
import org.mapstruct.ap.internal.model.annotation.AnnotationElement;
|
||||||
import org.mapstruct.ap.internal.model.annotation.AnnotationElement.AnnotationElementType;
|
import org.mapstruct.ap.internal.model.annotation.AnnotationElement.AnnotationElementType;
|
||||||
@ -42,7 +43,7 @@ public class Jsr330ComponentProcessor extends AnnotationBasedComponentModelProce
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<Annotation> getDecoratorAnnotations() {
|
protected List<Annotation> getDecoratorAnnotations(Decorator decorator) {
|
||||||
return Arrays.asList( singleton(), named() );
|
return Arrays.asList( singleton(), named() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ import org.mapstruct.ap.internal.gem.MapperGem;
|
|||||||
import org.mapstruct.ap.internal.gem.MappingInheritanceStrategyGem;
|
import org.mapstruct.ap.internal.gem.MappingInheritanceStrategyGem;
|
||||||
import org.mapstruct.ap.internal.gem.NullValueMappingStrategyGem;
|
import org.mapstruct.ap.internal.gem.NullValueMappingStrategyGem;
|
||||||
import org.mapstruct.ap.internal.model.AdditionalAnnotationsBuilder;
|
import org.mapstruct.ap.internal.model.AdditionalAnnotationsBuilder;
|
||||||
|
import org.mapstruct.ap.internal.model.Annotation;
|
||||||
import org.mapstruct.ap.internal.model.BeanMappingMethod;
|
import org.mapstruct.ap.internal.model.BeanMappingMethod;
|
||||||
import org.mapstruct.ap.internal.model.ContainerMappingMethod;
|
import org.mapstruct.ap.internal.model.ContainerMappingMethod;
|
||||||
import org.mapstruct.ap.internal.model.ContainerMappingMethodBuilder;
|
import org.mapstruct.ap.internal.model.ContainerMappingMethodBuilder;
|
||||||
@ -287,6 +288,9 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
|||||||
messager.printMessage( element, decoratedWith.mirror(), Message.DECORATOR_CONSTRUCTOR );
|
messager.printMessage( element, decoratedWith.mirror(), Message.DECORATOR_CONSTRUCTOR );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get annotations from the decorator class
|
||||||
|
Set<Annotation> decoratorAnnotations = additionalAnnotationsBuilder.getProcessedAnnotations( decoratorElement );
|
||||||
|
|
||||||
Decorator decorator = new Decorator.Builder()
|
Decorator decorator = new Decorator.Builder()
|
||||||
.elementUtils( elementUtils )
|
.elementUtils( elementUtils )
|
||||||
.typeFactory( typeFactory )
|
.typeFactory( typeFactory )
|
||||||
@ -300,6 +304,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
|||||||
.implPackage( mapperOptions.implementationPackage() )
|
.implPackage( mapperOptions.implementationPackage() )
|
||||||
.extraImports( getExtraImports( element, mapperOptions ) )
|
.extraImports( getExtraImports( element, mapperOptions ) )
|
||||||
.suppressGeneratorTimestamp( mapperOptions.suppressTimestampInGenerated() )
|
.suppressGeneratorTimestamp( mapperOptions.suppressTimestampInGenerated() )
|
||||||
|
.additionalAnnotations( decoratorAnnotations )
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
return decorator;
|
return decorator;
|
||||||
|
@ -9,20 +9,22 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import org.mapstruct.ap.internal.gem.MappingConstantsGem;
|
|
||||||
import org.mapstruct.ap.internal.model.Annotation;
|
|
||||||
import org.mapstruct.ap.internal.model.Mapper;
|
|
||||||
import org.mapstruct.ap.internal.model.annotation.AnnotationElement;
|
|
||||||
import org.mapstruct.ap.internal.model.annotation.AnnotationElement.AnnotationElementType;
|
|
||||||
|
|
||||||
import javax.lang.model.element.AnnotationMirror;
|
import javax.lang.model.element.AnnotationMirror;
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
import javax.lang.model.element.PackageElement;
|
import javax.lang.model.element.PackageElement;
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.internal.gem.MappingConstantsGem;
|
||||||
|
import org.mapstruct.ap.internal.model.Annotation;
|
||||||
|
import org.mapstruct.ap.internal.model.Decorator;
|
||||||
|
import org.mapstruct.ap.internal.model.Mapper;
|
||||||
|
import org.mapstruct.ap.internal.model.annotation.AnnotationElement;
|
||||||
|
import org.mapstruct.ap.internal.model.annotation.AnnotationElement.AnnotationElementType;
|
||||||
|
|
||||||
import static javax.lang.model.element.ElementKind.PACKAGE;
|
import static javax.lang.model.element.ElementKind.PACKAGE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,6 +37,9 @@ import static javax.lang.model.element.ElementKind.PACKAGE;
|
|||||||
*/
|
*/
|
||||||
public class SpringComponentProcessor extends AnnotationBasedComponentModelProcessor {
|
public class SpringComponentProcessor extends AnnotationBasedComponentModelProcessor {
|
||||||
|
|
||||||
|
private static final String SPRING_COMPONENT_ANNOTATION = "org.springframework.stereotype.Component";
|
||||||
|
private static final String SPRING_PRIMARY_ANNOTATION = "org.springframework.context.annotation.Primary";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getComponentModelIdentifier() {
|
protected String getComponentModelIdentifier() {
|
||||||
return MappingConstantsGem.ComponentModelGem.SPRING;
|
return MappingConstantsGem.ComponentModelGem.SPRING;
|
||||||
@ -54,12 +59,37 @@ public class SpringComponentProcessor extends AnnotationBasedComponentModelProce
|
|||||||
return typeAnnotations;
|
return typeAnnotations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the annotations that need to be added to the generated decorator, filtering out any annotations
|
||||||
|
* that are already present or represented as meta-annotations.
|
||||||
|
*
|
||||||
|
* @param decorator the decorator to process
|
||||||
|
* @return A list of annotations that should be added to the generated decorator.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected List<Annotation> getDecoratorAnnotations() {
|
protected List<Annotation> getDecoratorAnnotations(Decorator decorator) {
|
||||||
return Arrays.asList(
|
Set<String> desiredAnnotationNames = new LinkedHashSet<>();
|
||||||
component(),
|
desiredAnnotationNames.add( SPRING_COMPONENT_ANNOTATION );
|
||||||
primary()
|
desiredAnnotationNames.add( SPRING_PRIMARY_ANNOTATION );
|
||||||
);
|
List<Annotation> decoratorAnnotations = decorator.getAnnotations();
|
||||||
|
if ( !decoratorAnnotations.isEmpty() ) {
|
||||||
|
Set<Element> handledElements = new HashSet<>();
|
||||||
|
for ( Annotation annotation : decoratorAnnotations ) {
|
||||||
|
removeAnnotationsPresentOnElement(
|
||||||
|
annotation.getType().getTypeElement(),
|
||||||
|
desiredAnnotationNames,
|
||||||
|
handledElements
|
||||||
|
);
|
||||||
|
if ( desiredAnnotationNames.isEmpty() ) {
|
||||||
|
// If all annotations are removed, we can stop further processing
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return desiredAnnotationNames.stream()
|
||||||
|
.map( this::createAnnotation )
|
||||||
|
.collect( Collectors.toList() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -82,8 +112,12 @@ public class SpringComponentProcessor extends AnnotationBasedComponentModelProce
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Annotation createAnnotation(String canonicalName) {
|
||||||
|
return new Annotation( getTypeFactory().getType( canonicalName ) );
|
||||||
|
}
|
||||||
|
|
||||||
private Annotation autowired() {
|
private Annotation autowired() {
|
||||||
return new Annotation( getTypeFactory().getType( "org.springframework.beans.factory.annotation.Autowired" ) );
|
return createAnnotation( "org.springframework.beans.factory.annotation.Autowired" );
|
||||||
}
|
}
|
||||||
|
|
||||||
private Annotation qualifierDelegate() {
|
private Annotation qualifierDelegate() {
|
||||||
@ -96,34 +130,51 @@ public class SpringComponentProcessor extends AnnotationBasedComponentModelProce
|
|||||||
) ) );
|
) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private Annotation primary() {
|
|
||||||
return new Annotation( getTypeFactory().getType( "org.springframework.context.annotation.Primary" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
private Annotation component() {
|
private Annotation component() {
|
||||||
return new Annotation( getTypeFactory().getType( "org.springframework.stereotype.Component" ) );
|
return createAnnotation( SPRING_COMPONENT_ANNOTATION );
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAlreadyAnnotatedAsSpringStereotype(Mapper mapper) {
|
private boolean isAlreadyAnnotatedAsSpringStereotype(Mapper mapper) {
|
||||||
Set<Element> handledElements = new HashSet<>();
|
Set<String> desiredAnnotationNames = new LinkedHashSet<>();
|
||||||
return mapper.getAnnotations()
|
desiredAnnotationNames.add( SPRING_COMPONENT_ANNOTATION );
|
||||||
.stream()
|
|
||||||
.anyMatch(
|
List<Annotation> mapperAnnotations = mapper.getAnnotations();
|
||||||
annotation -> isOrIncludesComponentAnnotation( annotation, handledElements )
|
if ( !mapperAnnotations.isEmpty() ) {
|
||||||
);
|
Set<Element> handledElements = new HashSet<>();
|
||||||
|
for ( Annotation annotation : mapperAnnotations ) {
|
||||||
|
removeAnnotationsPresentOnElement(
|
||||||
|
annotation.getType().getTypeElement(),
|
||||||
|
desiredAnnotationNames,
|
||||||
|
handledElements
|
||||||
|
);
|
||||||
|
if ( desiredAnnotationNames.isEmpty() ) {
|
||||||
|
// If all annotations are removed, we can stop further processing
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isOrIncludesComponentAnnotation(Annotation annotation, Set<Element> handledElements) {
|
/**
|
||||||
return isOrIncludesComponentAnnotation(
|
* Removes all the annotations and meta-annotations from {@code annotations} which are on the given element.
|
||||||
annotation.getType().getTypeElement(), handledElements
|
*
|
||||||
);
|
* @param element the element to check
|
||||||
}
|
* @param annotations the annotations to check for
|
||||||
|
* @param handledElements set of already handled elements to avoid infinite recursion
|
||||||
private boolean isOrIncludesComponentAnnotation(Element element, Set<Element> handledElements) {
|
*/
|
||||||
if ( "org.springframework.stereotype.Component".equals(
|
private void removeAnnotationsPresentOnElement(Element element, Set<String> annotations,
|
||||||
( (TypeElement) element ).getQualifiedName().toString()
|
Set<Element> handledElements) {
|
||||||
)) {
|
if ( annotations.isEmpty() ) {
|
||||||
return true;
|
return;
|
||||||
|
}
|
||||||
|
if ( element instanceof TypeElement &&
|
||||||
|
annotations.remove( ( (TypeElement) element ).getQualifiedName().toString() ) ) {
|
||||||
|
if ( annotations.isEmpty() ) {
|
||||||
|
// If all annotations are removed, we can stop further processing
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( AnnotationMirror annotationMirror : element.getAnnotationMirrors() ) {
|
for ( AnnotationMirror annotationMirror : element.getAnnotationMirrors() ) {
|
||||||
@ -132,17 +183,16 @@ public class SpringComponentProcessor extends AnnotationBasedComponentModelProce
|
|||||||
if ( !isAnnotationInPackage( annotationMirrorElement, "java.lang.annotation" ) &&
|
if ( !isAnnotationInPackage( annotationMirrorElement, "java.lang.annotation" ) &&
|
||||||
!handledElements.contains( annotationMirrorElement ) ) {
|
!handledElements.contains( annotationMirrorElement ) ) {
|
||||||
handledElements.add( annotationMirrorElement );
|
handledElements.add( annotationMirrorElement );
|
||||||
boolean isOrIncludesComponentAnnotation = isOrIncludesComponentAnnotation(
|
if ( annotations.remove( ( (TypeElement) annotationMirrorElement ).getQualifiedName().toString() ) ) {
|
||||||
annotationMirrorElement, handledElements
|
if ( annotations.isEmpty() ) {
|
||||||
);
|
// If all annotations are removed, we can stop further processing
|
||||||
|
return;
|
||||||
if ( isOrIncludesComponentAnnotation ) {
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
removeAnnotationsPresentOnElement( element, annotations, handledElements );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PackageElement getPackageOf( Element element ) {
|
private PackageElement getPackageOf( Element element ) {
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.decorator;
|
||||||
|
|
||||||
|
import org.mapstruct.DecoratedWith;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
@DecoratedWith(AnnotatedMapperDecorator.class)
|
||||||
|
public interface AnnotatedMapper {
|
||||||
|
|
||||||
|
AnnotatedMapper INSTANCE = Mappers.getMapper( AnnotatedMapper.class );
|
||||||
|
|
||||||
|
Target toTarget(Source source);
|
||||||
|
|
||||||
|
class Source {
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Target {
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.decorator;
|
||||||
|
|
||||||
|
import org.mapstruct.AnnotateWith;
|
||||||
|
|
||||||
|
@AnnotateWith(value = TestAnnotation.class, elements = @AnnotateWith.Element(strings = "decoratorValue"))
|
||||||
|
public abstract class AnnotatedMapperDecorator implements AnnotatedMapper {
|
||||||
|
|
||||||
|
private final AnnotatedMapper delegate;
|
||||||
|
|
||||||
|
public AnnotatedMapperDecorator(AnnotatedMapper delegate) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.decorator;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.testutil.IssueKey;
|
||||||
|
import org.mapstruct.ap.testutil.ProcessorTest;
|
||||||
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for the application of @AnnotatedWith on decorator classes.
|
||||||
|
*/
|
||||||
|
@IssueKey("3659")
|
||||||
|
@WithClasses({
|
||||||
|
TestAnnotation.class,
|
||||||
|
AnnotatedMapper.class,
|
||||||
|
AnnotatedMapperDecorator.class
|
||||||
|
})
|
||||||
|
public class DecoratedWithAnnotatedWithTest {
|
||||||
|
|
||||||
|
@ProcessorTest
|
||||||
|
public void shouldApplyAnnotationFromDecorator() {
|
||||||
|
Class<?> implementationClass = AnnotatedMapper.INSTANCE.getClass();
|
||||||
|
|
||||||
|
assertThat( implementationClass ).hasAnnotation( TestAnnotation.class );
|
||||||
|
assertThat( implementationClass.getAnnotation( TestAnnotation.class ).value() ).isEqualTo( "decoratorValue" );
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.decorator;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test annotation for testing @AnnotatedWith on decorators.
|
||||||
|
*/
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface TestAnnotation {
|
||||||
|
String value() default "";
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.decorator.jakarta.annotatewith;
|
||||||
|
|
||||||
|
import org.mapstruct.DecoratedWith;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.MappingConstants;
|
||||||
|
import org.mapstruct.ap.test.decorator.Address;
|
||||||
|
import org.mapstruct.ap.test.decorator.AddressDto;
|
||||||
|
import org.mapstruct.ap.test.decorator.Person;
|
||||||
|
import org.mapstruct.ap.test.decorator.PersonDto;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mapper using Jakarta component model with a decorator.
|
||||||
|
*/
|
||||||
|
@Mapper(componentModel = MappingConstants.ComponentModel.JAKARTA)
|
||||||
|
@DecoratedWith(JakartaAnnotateWithWithMapperDecorator.class)
|
||||||
|
public interface JakartaAnnotateWithMapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps a person to a person DTO.
|
||||||
|
*
|
||||||
|
* @param person the person to map
|
||||||
|
* @return the person DTO
|
||||||
|
*/
|
||||||
|
@Mapping(target = "name", ignore = true)
|
||||||
|
PersonDto personToPersonDto(Person person);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps an address to an address DTO.
|
||||||
|
*
|
||||||
|
* @param address the address to map
|
||||||
|
* @return the address DTO
|
||||||
|
*/
|
||||||
|
AddressDto addressToAddressDto(Address address);
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.decorator.jakarta.annotatewith;
|
||||||
|
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.inject.Named;
|
||||||
|
import org.mapstruct.AnnotateWith;
|
||||||
|
import org.mapstruct.ap.test.decorator.Person;
|
||||||
|
import org.mapstruct.ap.test.decorator.PersonDto;
|
||||||
|
import org.mapstruct.ap.test.decorator.TestAnnotation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A decorator for {@link JakartaAnnotateWithMapper}.
|
||||||
|
*/
|
||||||
|
@AnnotateWith(value = TestAnnotation.class)
|
||||||
|
public abstract class JakartaAnnotateWithWithMapperDecorator implements JakartaAnnotateWithMapper {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
@Named("org.mapstruct.ap.test.decorator.jakarta.annotatewith.JakartaAnnotateWithMapperImpl_")
|
||||||
|
private JakartaAnnotateWithMapper delegate;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PersonDto personToPersonDto(Person person) {
|
||||||
|
PersonDto dto = delegate.personToPersonDto( person );
|
||||||
|
dto.setName( person.getFirstName() + " " + person.getLastName() );
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.decorator.jakarta.annotatewith;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
import org.mapstruct.ap.test.decorator.Address;
|
||||||
|
import org.mapstruct.ap.test.decorator.AddressDto;
|
||||||
|
import org.mapstruct.ap.test.decorator.Person;
|
||||||
|
import org.mapstruct.ap.test.decorator.PersonDto;
|
||||||
|
import org.mapstruct.ap.test.decorator.TestAnnotation;
|
||||||
|
import org.mapstruct.ap.testutil.IssueKey;
|
||||||
|
import org.mapstruct.ap.testutil.ProcessorTest;
|
||||||
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
|
import org.mapstruct.ap.testutil.WithJakartaInject;
|
||||||
|
import org.mapstruct.ap.testutil.runner.GeneratedSource;
|
||||||
|
|
||||||
|
import static java.lang.System.lineSeparator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for the application of @AnnotateWith on decorator classes with Jakarta component model.
|
||||||
|
*/
|
||||||
|
@IssueKey("3659")
|
||||||
|
@WithClasses({
|
||||||
|
Person.class,
|
||||||
|
PersonDto.class,
|
||||||
|
Address.class,
|
||||||
|
AddressDto.class,
|
||||||
|
JakartaAnnotateWithMapper.class,
|
||||||
|
TestAnnotation.class,
|
||||||
|
JakartaAnnotateWithWithMapperDecorator.class
|
||||||
|
})
|
||||||
|
@WithJakartaInject
|
||||||
|
public class JakartaDecoratorAnnotateWithTest {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
final GeneratedSource generatedSource = new GeneratedSource();
|
||||||
|
|
||||||
|
@ProcessorTest
|
||||||
|
public void hasCorrectImports() {
|
||||||
|
// check the decorator
|
||||||
|
generatedSource.forMapper( JakartaAnnotateWithMapper.class )
|
||||||
|
.content()
|
||||||
|
.contains( "import jakarta.inject.Inject;" )
|
||||||
|
.contains( "import jakarta.inject.Named;" )
|
||||||
|
.contains( "import jakarta.inject.Singleton;" )
|
||||||
|
.contains( "@TestAnnotation" )
|
||||||
|
.contains( "@Singleton" + lineSeparator() + "@Named" )
|
||||||
|
.doesNotContain( "javax.inject" );
|
||||||
|
// check the plain mapper
|
||||||
|
generatedSource.forDecoratedMapper( JakartaAnnotateWithMapper.class ).content()
|
||||||
|
.contains( "import jakarta.inject.Named;" )
|
||||||
|
.contains( "import jakarta.inject.Singleton;" )
|
||||||
|
.contains( "@Singleton" + lineSeparator() + "@Named" )
|
||||||
|
.doesNotContain( "javax.inject" );
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@ import org.mapstruct.ap.test.decorator.Address;
|
|||||||
import org.mapstruct.ap.test.decorator.AddressDto;
|
import org.mapstruct.ap.test.decorator.AddressDto;
|
||||||
import org.mapstruct.ap.test.decorator.Person;
|
import org.mapstruct.ap.test.decorator.Person;
|
||||||
import org.mapstruct.ap.test.decorator.PersonDto;
|
import org.mapstruct.ap.test.decorator.PersonDto;
|
||||||
|
import org.mapstruct.ap.test.decorator.jsr330.annotatewith.Jsr330DecoratorAnnotateWithTest;
|
||||||
import org.mapstruct.ap.testutil.IssueKey;
|
import org.mapstruct.ap.testutil.IssueKey;
|
||||||
import org.mapstruct.ap.testutil.ProcessorTest;
|
import org.mapstruct.ap.testutil.ProcessorTest;
|
||||||
import org.mapstruct.ap.testutil.WithClasses;
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
@ -27,6 +28,7 @@ import org.springframework.context.ConfigurableApplicationContext;
|
|||||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.FilterType;
|
||||||
|
|
||||||
import static java.lang.System.lineSeparator;
|
import static java.lang.System.lineSeparator;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@ -45,7 +47,13 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
PersonMapperDecorator.class
|
PersonMapperDecorator.class
|
||||||
})
|
})
|
||||||
@IssueKey("592")
|
@IssueKey("592")
|
||||||
@ComponentScan(basePackageClasses = Jsr330DecoratorTest.class)
|
@ComponentScan(
|
||||||
|
basePackageClasses = Jsr330DecoratorTest.class,
|
||||||
|
excludeFilters = @ComponentScan.Filter(
|
||||||
|
type = FilterType.ASSIGNABLE_TYPE,
|
||||||
|
classes = { Jsr330DecoratorAnnotateWithTest.class }
|
||||||
|
)
|
||||||
|
)
|
||||||
@Configuration
|
@Configuration
|
||||||
@WithJavaxInject
|
@WithJavaxInject
|
||||||
@DisabledOnJre(JRE.OTHER)
|
@DisabledOnJre(JRE.OTHER)
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.decorator.jsr330.annotatewith;
|
||||||
|
|
||||||
|
import org.mapstruct.DecoratedWith;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.MappingConstants;
|
||||||
|
import org.mapstruct.ap.test.decorator.Address;
|
||||||
|
import org.mapstruct.ap.test.decorator.AddressDto;
|
||||||
|
import org.mapstruct.ap.test.decorator.Person;
|
||||||
|
import org.mapstruct.ap.test.decorator.PersonDto;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mapper using JSR-330 component model with a decorator.
|
||||||
|
*/
|
||||||
|
@Mapper(componentModel = MappingConstants.ComponentModel.JSR330)
|
||||||
|
@DecoratedWith(Jsr330AnnotateWithMapperDecorator.class)
|
||||||
|
public interface Jsr330AnnotateWithMapper {
|
||||||
|
|
||||||
|
@Mapping(target = "name", ignore = true)
|
||||||
|
PersonDto personToPersonDto(Person person);
|
||||||
|
|
||||||
|
AddressDto addressToAddressDto(Address address);
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.decorator.jsr330.annotatewith;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Named;
|
||||||
|
|
||||||
|
import org.mapstruct.AnnotateWith;
|
||||||
|
import org.mapstruct.ap.test.decorator.Person;
|
||||||
|
import org.mapstruct.ap.test.decorator.PersonDto;
|
||||||
|
import org.mapstruct.ap.test.decorator.TestAnnotation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A decorator for {@link Jsr330AnnotateWithMapper}.
|
||||||
|
*/
|
||||||
|
@AnnotateWith(value = TestAnnotation.class)
|
||||||
|
public abstract class Jsr330AnnotateWithMapperDecorator implements Jsr330AnnotateWithMapper {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
@Named("org.mapstruct.ap.test.decorator.jsr330.annotatewith.Jsr330AnnotateWithMapperImpl_")
|
||||||
|
private Jsr330AnnotateWithMapper delegate;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PersonDto personToPersonDto(Person person) {
|
||||||
|
PersonDto dto = delegate.personToPersonDto( person );
|
||||||
|
dto.setName( person.getFirstName() + " " + person.getLastName() );
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.decorator.jsr330.annotatewith;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Named;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.condition.DisabledOnJre;
|
||||||
|
import org.junit.jupiter.api.condition.JRE;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
import org.mapstruct.ap.test.decorator.Address;
|
||||||
|
import org.mapstruct.ap.test.decorator.AddressDto;
|
||||||
|
import org.mapstruct.ap.test.decorator.Person;
|
||||||
|
import org.mapstruct.ap.test.decorator.PersonDto;
|
||||||
|
import org.mapstruct.ap.test.decorator.TestAnnotation;
|
||||||
|
import org.mapstruct.ap.testutil.IssueKey;
|
||||||
|
import org.mapstruct.ap.testutil.ProcessorTest;
|
||||||
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
|
import org.mapstruct.ap.testutil.WithJavaxInject;
|
||||||
|
import org.mapstruct.ap.testutil.runner.GeneratedSource;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for the application of @AnnotateWith on decorator classes with JSR-330 component model.
|
||||||
|
*/
|
||||||
|
@IssueKey("3659")
|
||||||
|
@WithClasses({
|
||||||
|
Person.class,
|
||||||
|
PersonDto.class,
|
||||||
|
Address.class,
|
||||||
|
AddressDto.class,
|
||||||
|
Jsr330AnnotateWithMapper.class,
|
||||||
|
Jsr330AnnotateWithMapperDecorator.class,
|
||||||
|
TestAnnotation.class
|
||||||
|
})
|
||||||
|
@ComponentScan(basePackageClasses = Jsr330DecoratorAnnotateWithTest.class)
|
||||||
|
@Configuration
|
||||||
|
@WithJavaxInject
|
||||||
|
@DisabledOnJre(JRE.OTHER)
|
||||||
|
public class Jsr330DecoratorAnnotateWithTest {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
final GeneratedSource generatedSource = new GeneratedSource();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
@Named
|
||||||
|
private Jsr330AnnotateWithMapper jsr330AnnotateWithMapper;
|
||||||
|
|
||||||
|
private ConfigurableApplicationContext context;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void springUp() {
|
||||||
|
context = new AnnotationConfigApplicationContext( getClass() );
|
||||||
|
context.getAutowireCapableBeanFactory().autowireBean( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void springDown() {
|
||||||
|
if ( context != null ) {
|
||||||
|
context.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ProcessorTest
|
||||||
|
public void shouldContainCustomAnnotation() {
|
||||||
|
generatedSource.forMapper( Jsr330AnnotateWithMapper.class )
|
||||||
|
.content()
|
||||||
|
.contains( "@TestAnnotation" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@ProcessorTest
|
||||||
|
public void shouldInvokeDecoratorMethods() {
|
||||||
|
Calendar birthday = Calendar.getInstance();
|
||||||
|
birthday.set( 1928, Calendar.MAY, 23 );
|
||||||
|
Person person = new Person( "Gary", "Crant", birthday.getTime(), new Address( "42 Ocean View Drive" ) );
|
||||||
|
|
||||||
|
PersonDto personDto = jsr330AnnotateWithMapper.personToPersonDto( person );
|
||||||
|
|
||||||
|
assertThat( personDto ).isNotNull();
|
||||||
|
assertThat( personDto.getName() ).isEqualTo( "Gary Crant" );
|
||||||
|
assertThat( personDto.getAddress() ).isNotNull();
|
||||||
|
assertThat( personDto.getAddress().getAddressLine() ).isEqualTo( "42 Ocean View Drive" );
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.decorator.spring.annotatewith;
|
||||||
|
|
||||||
|
import org.mapstruct.DecoratedWith;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.MappingConstants;
|
||||||
|
import org.mapstruct.ap.test.decorator.Address;
|
||||||
|
import org.mapstruct.ap.test.decorator.AddressDto;
|
||||||
|
import org.mapstruct.ap.test.decorator.Person;
|
||||||
|
import org.mapstruct.ap.test.decorator.PersonDto;
|
||||||
|
|
||||||
|
@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
|
||||||
|
@DecoratedWith(AnnotateMapperDecorator.class)
|
||||||
|
public interface AnnotateMapper {
|
||||||
|
|
||||||
|
@Mapping(target = "name", ignore = true)
|
||||||
|
PersonDto personToPersonDto(Person person);
|
||||||
|
|
||||||
|
AddressDto addressToAddressDto(Address address);
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.decorator.spring.annotatewith;
|
||||||
|
|
||||||
|
import org.mapstruct.AnnotateWith;
|
||||||
|
import org.mapstruct.ap.test.decorator.Person;
|
||||||
|
import org.mapstruct.ap.test.decorator.PersonDto;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@AnnotateWith(value = Component.class, elements = @AnnotateWith.Element(strings = "decoratorComponent"))
|
||||||
|
@AnnotateWith(value = Primary.class)
|
||||||
|
public abstract class AnnotateMapperDecorator implements AnnotateMapper {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("delegate")
|
||||||
|
private AnnotateMapper delegate;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PersonDto personToPersonDto(Person person) {
|
||||||
|
PersonDto dto = delegate.personToPersonDto( person );
|
||||||
|
dto.setName( person.getFirstName() + " " + person.getLastName() );
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.decorator.spring.annotatewith;
|
||||||
|
|
||||||
|
import org.mapstruct.DecoratedWith;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.MappingConstants;
|
||||||
|
import org.mapstruct.ap.test.decorator.Address;
|
||||||
|
import org.mapstruct.ap.test.decorator.AddressDto;
|
||||||
|
import org.mapstruct.ap.test.decorator.Person;
|
||||||
|
import org.mapstruct.ap.test.decorator.PersonDto;
|
||||||
|
|
||||||
|
@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
|
||||||
|
@DecoratedWith(CustomAnnotateMapperDecorator.class)
|
||||||
|
public interface CustomAnnotateMapper {
|
||||||
|
|
||||||
|
@Mapping(target = "name", ignore = true)
|
||||||
|
PersonDto personToPersonDto(Person person);
|
||||||
|
|
||||||
|
AddressDto addressToAddressDto(Address address);
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.decorator.spring.annotatewith;
|
||||||
|
|
||||||
|
import org.mapstruct.AnnotateWith;
|
||||||
|
import org.mapstruct.ap.test.decorator.Person;
|
||||||
|
import org.mapstruct.ap.test.decorator.PersonDto;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
|
||||||
|
@AnnotateWith(value = CustomComponent.class, elements = @AnnotateWith.Element(strings = "customComponentDecorator"))
|
||||||
|
@AnnotateWith(value = CustomPrimary.class)
|
||||||
|
public abstract class CustomAnnotateMapperDecorator implements CustomAnnotateMapper {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("delegate")
|
||||||
|
private CustomAnnotateMapper delegate;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PersonDto personToPersonDto(Person person) {
|
||||||
|
PersonDto dto = delegate.personToPersonDto( person );
|
||||||
|
dto.setName( person.getFirstName() + " " + person.getLastName() );
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.decorator.spring.annotatewith;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Component
|
||||||
|
public @interface CustomComponent {
|
||||||
|
String value() default "";
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.decorator.spring.annotatewith;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
|
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Primary
|
||||||
|
public @interface CustomPrimary {
|
||||||
|
}
|
@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.decorator.spring.annotatewith;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
import org.mapstruct.ap.test.decorator.Address;
|
||||||
|
import org.mapstruct.ap.test.decorator.AddressDto;
|
||||||
|
import org.mapstruct.ap.test.decorator.Person;
|
||||||
|
import org.mapstruct.ap.test.decorator.PersonDto;
|
||||||
|
import org.mapstruct.ap.testutil.IssueKey;
|
||||||
|
import org.mapstruct.ap.testutil.ProcessorTest;
|
||||||
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
|
import org.mapstruct.ap.testutil.WithSpring;
|
||||||
|
import org.mapstruct.ap.testutil.runner.GeneratedSource;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for the application of @AnnotateWith on decorator classes with Spring component model.
|
||||||
|
*/
|
||||||
|
@IssueKey("3659")
|
||||||
|
@WithClasses({
|
||||||
|
Person.class,
|
||||||
|
PersonDto.class,
|
||||||
|
Address.class,
|
||||||
|
AddressDto.class,
|
||||||
|
AnnotateMapper.class,
|
||||||
|
AnnotateMapperDecorator.class,
|
||||||
|
CustomComponent.class,
|
||||||
|
CustomPrimary.class,
|
||||||
|
CustomAnnotateMapper.class,
|
||||||
|
CustomAnnotateMapperDecorator.class
|
||||||
|
})
|
||||||
|
@WithSpring
|
||||||
|
@ComponentScan(basePackageClasses = SpringDecoratorAnnotateWithTest.class)
|
||||||
|
@Configuration
|
||||||
|
public class SpringDecoratorAnnotateWithTest {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
final GeneratedSource generatedSource = new GeneratedSource();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AnnotateMapper annotateMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CustomAnnotateMapper customAnnotateMapper;
|
||||||
|
|
||||||
|
private ConfigurableApplicationContext context;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void springUp() {
|
||||||
|
context = new AnnotationConfigApplicationContext( getClass() );
|
||||||
|
context.getAutowireCapableBeanFactory().autowireBean( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void springDown() {
|
||||||
|
if ( context != null ) {
|
||||||
|
context.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ProcessorTest
|
||||||
|
public void shouldNotDuplicateComponentAnnotation() {
|
||||||
|
generatedSource.forMapper( AnnotateMapper.class )
|
||||||
|
.content()
|
||||||
|
.contains( "@Component(value = \"decoratorComponent\")", "@Primary" )
|
||||||
|
.doesNotContain( "@Component" + System.lineSeparator() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@ProcessorTest
|
||||||
|
public void shouldNotDuplicateCustomComponentAnnotation() {
|
||||||
|
generatedSource.forMapper( CustomAnnotateMapper.class )
|
||||||
|
.content()
|
||||||
|
.contains( "@CustomComponent(value = \"customComponentDecorator\")", "@CustomPrimary" )
|
||||||
|
.doesNotContain( "@Component" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@ProcessorTest
|
||||||
|
public void shouldInvokeAnnotateDecoratorMethods() {
|
||||||
|
Calendar birthday = Calendar.getInstance();
|
||||||
|
birthday.set( 1928, Calendar.MAY, 23 );
|
||||||
|
Person person = new Person( "Gary", "Crant", birthday.getTime(), new Address( "42 Ocean View Drive" ) );
|
||||||
|
|
||||||
|
PersonDto personDto = annotateMapper.personToPersonDto( person );
|
||||||
|
|
||||||
|
assertThat( personDto ).isNotNull();
|
||||||
|
assertThat( personDto.getName() ).isEqualTo( "Gary Crant" );
|
||||||
|
assertThat( personDto.getAddress() ).isNotNull();
|
||||||
|
assertThat( personDto.getAddress().getAddressLine() ).isEqualTo( "42 Ocean View Drive" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@ProcessorTest
|
||||||
|
public void shouldInvokeCustomAnnotateDecoratorMethods() {
|
||||||
|
Calendar birthday = Calendar.getInstance();
|
||||||
|
birthday.set( 1928, Calendar.MAY, 23 );
|
||||||
|
Person person = new Person( "Gary", "Crant", birthday.getTime(), new Address( "42 Ocean View Drive" ) );
|
||||||
|
|
||||||
|
PersonDto personDto = customAnnotateMapper.personToPersonDto( person );
|
||||||
|
|
||||||
|
assertThat( personDto ).isNotNull();
|
||||||
|
assertThat( personDto.getName() ).isEqualTo( "Gary Crant" );
|
||||||
|
assertThat( personDto.getAddress() ).isNotNull();
|
||||||
|
assertThat( personDto.getAddress().getAddressLine() ).isEqualTo( "42 Ocean View Drive" );
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user