From daaa99d143f29e2305c672e7d5cffc866e36236b Mon Sep 17 00:00:00 2001 From: Gunnar Morling Date: Wed, 3 Jun 2015 21:47:20 +0200 Subject: [PATCH] #272 Allowing to inject decorated mapper in Spring without qualifier --- .../cdi/DecoratedSourceTargetMapper.java | 1 - .../spring/SourceTargetMapperDecorator.java | 4 +++- .../itest/spring/SpringBasedMapperTest.java | 5 ++-- .../ap/internal/model/Annotation.java | 15 ++++++++++++ ...nnotationBasedComponentModelProcessor.java | 17 ++++++++------ .../processor/CdiComponentProcessor.java | 13 +++++++---- .../processor/Jsr330ComponentProcessor.java | 10 ++++---- .../processor/SpringComponentProcessor.java | 23 +++++++++++++++---- .../ap/internal/model/Annotation.ftl | 2 +- 9 files changed, 65 insertions(+), 25 deletions(-) diff --git a/integrationtest/src/test/resources/cdiTest/src/main/java/org/mapstruct/itest/cdi/DecoratedSourceTargetMapper.java b/integrationtest/src/test/resources/cdiTest/src/main/java/org/mapstruct/itest/cdi/DecoratedSourceTargetMapper.java index ec4cd7cf6..c8ea3e3e7 100644 --- a/integrationtest/src/test/resources/cdiTest/src/main/java/org/mapstruct/itest/cdi/DecoratedSourceTargetMapper.java +++ b/integrationtest/src/test/resources/cdiTest/src/main/java/org/mapstruct/itest/cdi/DecoratedSourceTargetMapper.java @@ -23,7 +23,6 @@ import org.mapstruct.DecoratedWith; import org.mapstruct.itest.cdi.other.DateMapper; @Mapper( componentModel = "cdi", uses = DateMapper.class ) -@DecoratedWith( SourceTargetMapperDecorator.class ) public interface DecoratedSourceTargetMapper { Target sourceToTarget(Source source); diff --git a/integrationtest/src/test/resources/springTest/src/main/java/org/mapstruct/itest/spring/SourceTargetMapperDecorator.java b/integrationtest/src/test/resources/springTest/src/main/java/org/mapstruct/itest/spring/SourceTargetMapperDecorator.java index a940a48f5..6ac7fe3cb 100644 --- a/integrationtest/src/test/resources/springTest/src/main/java/org/mapstruct/itest/spring/SourceTargetMapperDecorator.java +++ b/integrationtest/src/test/resources/springTest/src/main/java/org/mapstruct/itest/spring/SourceTargetMapperDecorator.java @@ -20,13 +20,15 @@ package org.mapstruct.itest.spring; 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; @Component +@Primary public class SourceTargetMapperDecorator implements DecoratedSourceTargetMapper { @Autowired - @Qualifier( "decoratedSourceTargetMapperImpl_" ) + @Qualifier( "delegate" ) private DecoratedSourceTargetMapper delegate; public SourceTargetMapperDecorator() { diff --git a/integrationtest/src/test/resources/springTest/src/test/java/org/mapstruct/itest/spring/SpringBasedMapperTest.java b/integrationtest/src/test/resources/springTest/src/test/java/org/mapstruct/itest/spring/SpringBasedMapperTest.java index b2cd1b879..7a75a4108 100644 --- a/integrationtest/src/test/resources/springTest/src/test/java/org/mapstruct/itest/spring/SpringBasedMapperTest.java +++ b/integrationtest/src/test/resources/springTest/src/test/java/org/mapstruct/itest/spring/SpringBasedMapperTest.java @@ -38,6 +38,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @ContextConfiguration(classes = SpringTestConfig.class ) @RunWith( SpringJUnit4ClassRunner.class ) public class SpringBasedMapperTest { + @Configuration @ComponentScan(basePackageClasses = SpringBasedMapperTest.class) public static class SpringTestConfig { @@ -47,7 +48,6 @@ public class SpringBasedMapperTest { private SourceTargetMapper mapper; @Autowired - @Qualifier( "sourceTargetMapperDecorator" ) private DecoratedSourceTargetMapper decoratedMapper; @Test @@ -70,5 +70,4 @@ public class SpringBasedMapperTest { assertThat( target ).isNotNull(); assertThat( target.getFoo() ).isEqualTo( Long.valueOf( 43 ) ); } - -} \ No newline at end of file +} diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/Annotation.java b/processor/src/main/java/org/mapstruct/ap/internal/model/Annotation.java index 02a2f5718..b3ea9d40c 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/Annotation.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/Annotation.java @@ -19,6 +19,7 @@ package org.mapstruct.ap.internal.model; import java.util.Collections; +import java.util.List; import java.util.Set; import org.mapstruct.ap.internal.model.common.ModelElement; @@ -33,8 +34,18 @@ public class Annotation extends ModelElement { private final Type type; + /** + * List of annotation attributes. Quite simplistic, but it's sufficient for now. + */ + private List properties; + public Annotation(Type type) { + this( type, Collections.emptyList() ); + } + + public Annotation(Type type, List properties) { this.type = type; + this.properties = properties; } public Type getType() { @@ -45,4 +56,8 @@ public class Annotation extends ModelElement { public Set getImportTypes() { return Collections.singleton( type ); } + + public List getProperties() { + return properties; + } } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/processor/AnnotationBasedComponentModelProcessor.java b/processor/src/main/java/org/mapstruct/ap/internal/processor/AnnotationBasedComponentModelProcessor.java index d0e592e5d..3e2b89a5e 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/processor/AnnotationBasedComponentModelProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/processor/AnnotationBasedComponentModelProcessor.java @@ -18,6 +18,7 @@ */ package org.mapstruct.ap.internal.processor; +import java.util.List; import java.util.ListIterator; import javax.lang.model.element.TypeElement; @@ -56,11 +57,13 @@ public abstract class AnnotationBasedComponentModelProcessor implements ModelEle return mapper; } - if ( shouldDecoratorBeRemoved() ) { - mapper.removeDecorator(); + for ( Annotation typeAnnotation : getTypeAnnotations( mapper ) ) { + mapper.addAnnotation( typeAnnotation ); } - mapper.addAnnotation( getTypeAnnotation() ); + if ( !requiresGenerationOfDecoratorClass() ) { + mapper.removeDecorator(); + } ListIterator iterator = mapper.getReferencedMappers().listIterator(); while ( iterator.hasNext() ) { @@ -92,9 +95,9 @@ public abstract class AnnotationBasedComponentModelProcessor implements ModelEle protected abstract String getComponentModelIdentifier(); /** - * @return the annotation of the mapper implementation + * @return the annotation(s) to be added at the mapper type implementation */ - protected abstract Annotation getTypeAnnotation(); + protected abstract List getTypeAnnotations(Mapper mapper); /** * @return the annotation of the field for the mapper reference @@ -102,9 +105,9 @@ public abstract class AnnotationBasedComponentModelProcessor implements ModelEle protected abstract Annotation getMapperReferenceAnnotation(); /** - * @return if generated decorator class should be removed + * @return if a decorator (sub-)class needs to be generated or not */ - protected abstract boolean shouldDecoratorBeRemoved(); + protected abstract boolean requiresGenerationOfDecoratorClass(); @Override public int getPriority() { diff --git a/processor/src/main/java/org/mapstruct/ap/internal/processor/CdiComponentProcessor.java b/processor/src/main/java/org/mapstruct/ap/internal/processor/CdiComponentProcessor.java index d7e11a07c..14f92ea69 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/processor/CdiComponentProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/processor/CdiComponentProcessor.java @@ -18,6 +18,9 @@ */ package org.mapstruct.ap.internal.processor; +import java.util.Collections; +import java.util.List; + import org.mapstruct.ap.internal.model.Annotation; import org.mapstruct.ap.internal.model.Mapper; @@ -36,8 +39,10 @@ public class CdiComponentProcessor extends AnnotationBasedComponentModelProcesso } @Override - protected Annotation getTypeAnnotation() { - return new Annotation( getTypeFactory().getType( "javax.enterprise.context.ApplicationScoped" ) ); + protected List getTypeAnnotations(Mapper mapper) { + return Collections.singletonList( + new Annotation( getTypeFactory().getType( "javax.enterprise.context.ApplicationScoped" ) ) + ); } @Override @@ -46,7 +51,7 @@ public class CdiComponentProcessor extends AnnotationBasedComponentModelProcesso } @Override - protected boolean shouldDecoratorBeRemoved() { - return true; + protected boolean requiresGenerationOfDecoratorClass() { + return false; } } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/processor/Jsr330ComponentProcessor.java b/processor/src/main/java/org/mapstruct/ap/internal/processor/Jsr330ComponentProcessor.java index 87f16d655..3bf6ce4bb 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/processor/Jsr330ComponentProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/processor/Jsr330ComponentProcessor.java @@ -20,6 +20,8 @@ package org.mapstruct.ap.internal.processor; import org.mapstruct.ap.internal.model.Annotation; import org.mapstruct.ap.internal.model.Mapper; +import java.util.Collections; +import java.util.List; /** * A {@link ModelElementProcessor} which converts the given {@link Mapper} @@ -36,8 +38,8 @@ public class Jsr330ComponentProcessor extends AnnotationBasedComponentModelProce } @Override - protected Annotation getTypeAnnotation() { - return new Annotation( getTypeFactory().getType( "javax.inject.Named" ) ); + protected List getTypeAnnotations(Mapper mapper) { + return Collections.singletonList( new Annotation( getTypeFactory().getType( "javax.inject.Named" ) ) ); } @Override @@ -46,7 +48,7 @@ public class Jsr330ComponentProcessor extends AnnotationBasedComponentModelProce } @Override - protected boolean shouldDecoratorBeRemoved() { - return false; + protected boolean requiresGenerationOfDecoratorClass() { + return true; } } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/processor/SpringComponentProcessor.java b/processor/src/main/java/org/mapstruct/ap/internal/processor/SpringComponentProcessor.java index 021e56c59..99d609f83 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/processor/SpringComponentProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/processor/SpringComponentProcessor.java @@ -18,6 +18,10 @@ */ package org.mapstruct.ap.internal.processor; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + import org.mapstruct.ap.internal.model.Annotation; import org.mapstruct.ap.internal.model.Mapper; @@ -36,8 +40,19 @@ public class SpringComponentProcessor extends AnnotationBasedComponentModelProce } @Override - protected Annotation getTypeAnnotation() { - return new Annotation( getTypeFactory().getType( "org.springframework.stereotype.Component" ) ); + protected List getTypeAnnotations(Mapper mapper) { + List typeAnnotations = new ArrayList(); + typeAnnotations.add( new Annotation( getTypeFactory().getType( "org.springframework.stereotype.Component" ) ) ); + + if ( mapper.getDecorator() != null ) { + Annotation qualifier = new Annotation( + getTypeFactory().getType( "org.springframework.beans.factory.annotation.Qualifier" ), + Arrays.asList( "\"delegate\"" ) + ); + typeAnnotations.add( qualifier ); + } + + return typeAnnotations; } @Override @@ -46,7 +61,7 @@ public class SpringComponentProcessor extends AnnotationBasedComponentModelProce } @Override - protected boolean shouldDecoratorBeRemoved() { - return true; + protected boolean requiresGenerationOfDecoratorClass() { + return false; } } diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/Annotation.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/Annotation.ftl index 98eb78b3d..8b9283401 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/Annotation.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/Annotation.ftl @@ -18,4 +18,4 @@ limitations under the License. --> -@<@includeModel object=type/> \ No newline at end of file +@<@includeModel object=type/><#if (properties?size > 0) >(<#list properties as property>${property}<#if property_has_next>, ) \ No newline at end of file