#272 Allowing to inject decorated mapper in Spring without qualifier

This commit is contained in:
Gunnar Morling 2015-06-03 21:47:20 +02:00
parent 2ad77b5aa0
commit daaa99d143
9 changed files with 65 additions and 25 deletions

View File

@ -23,7 +23,6 @@ import org.mapstruct.DecoratedWith;
import org.mapstruct.itest.cdi.other.DateMapper; import org.mapstruct.itest.cdi.other.DateMapper;
@Mapper( componentModel = "cdi", uses = DateMapper.class ) @Mapper( componentModel = "cdi", uses = DateMapper.class )
@DecoratedWith( SourceTargetMapperDecorator.class )
public interface DecoratedSourceTargetMapper { public interface DecoratedSourceTargetMapper {
Target sourceToTarget(Source source); Target sourceToTarget(Source source);

View File

@ -20,13 +20,15 @@ package org.mapstruct.itest.spring;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
@Primary
public class SourceTargetMapperDecorator implements DecoratedSourceTargetMapper { public class SourceTargetMapperDecorator implements DecoratedSourceTargetMapper {
@Autowired @Autowired
@Qualifier( "decoratedSourceTargetMapperImpl_" ) @Qualifier( "delegate" )
private DecoratedSourceTargetMapper delegate; private DecoratedSourceTargetMapper delegate;
public SourceTargetMapperDecorator() { public SourceTargetMapperDecorator() {

View File

@ -38,6 +38,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ContextConfiguration(classes = SpringTestConfig.class ) @ContextConfiguration(classes = SpringTestConfig.class )
@RunWith( SpringJUnit4ClassRunner.class ) @RunWith( SpringJUnit4ClassRunner.class )
public class SpringBasedMapperTest { public class SpringBasedMapperTest {
@Configuration @Configuration
@ComponentScan(basePackageClasses = SpringBasedMapperTest.class) @ComponentScan(basePackageClasses = SpringBasedMapperTest.class)
public static class SpringTestConfig { public static class SpringTestConfig {
@ -47,7 +48,6 @@ public class SpringBasedMapperTest {
private SourceTargetMapper mapper; private SourceTargetMapper mapper;
@Autowired @Autowired
@Qualifier( "sourceTargetMapperDecorator" )
private DecoratedSourceTargetMapper decoratedMapper; private DecoratedSourceTargetMapper decoratedMapper;
@Test @Test
@ -70,5 +70,4 @@ public class SpringBasedMapperTest {
assertThat( target ).isNotNull(); assertThat( target ).isNotNull();
assertThat( target.getFoo() ).isEqualTo( Long.valueOf( 43 ) ); assertThat( target.getFoo() ).isEqualTo( Long.valueOf( 43 ) );
} }
} }

View File

@ -19,6 +19,7 @@
package org.mapstruct.ap.internal.model; package org.mapstruct.ap.internal.model;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.Set; import java.util.Set;
import org.mapstruct.ap.internal.model.common.ModelElement; import org.mapstruct.ap.internal.model.common.ModelElement;
@ -33,8 +34,18 @@ public class Annotation extends ModelElement {
private final Type type; private final Type type;
/**
* List of annotation attributes. Quite simplistic, but it's sufficient for now.
*/
private List<String> properties;
public Annotation(Type type) { public Annotation(Type type) {
this( type, Collections.<String>emptyList() );
}
public Annotation(Type type, List<String> properties) {
this.type = type; this.type = type;
this.properties = properties;
} }
public Type getType() { public Type getType() {
@ -45,4 +56,8 @@ public class Annotation extends ModelElement {
public Set<Type> getImportTypes() { public Set<Type> getImportTypes() {
return Collections.singleton( type ); return Collections.singleton( type );
} }
public List<String> getProperties() {
return properties;
}
} }

View File

@ -18,6 +18,7 @@
*/ */
package org.mapstruct.ap.internal.processor; package org.mapstruct.ap.internal.processor;
import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeElement;
@ -56,11 +57,13 @@ public abstract class AnnotationBasedComponentModelProcessor implements ModelEle
return mapper; return mapper;
} }
if ( shouldDecoratorBeRemoved() ) { for ( Annotation typeAnnotation : getTypeAnnotations( mapper ) ) {
mapper.removeDecorator(); mapper.addAnnotation( typeAnnotation );
} }
mapper.addAnnotation( getTypeAnnotation() ); if ( !requiresGenerationOfDecoratorClass() ) {
mapper.removeDecorator();
}
ListIterator<MapperReference> iterator = mapper.getReferencedMappers().listIterator(); ListIterator<MapperReference> iterator = mapper.getReferencedMappers().listIterator();
while ( iterator.hasNext() ) { while ( iterator.hasNext() ) {
@ -92,9 +95,9 @@ public abstract class AnnotationBasedComponentModelProcessor implements ModelEle
protected abstract String getComponentModelIdentifier(); 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<Annotation> getTypeAnnotations(Mapper mapper);
/** /**
* @return the annotation of the field for the mapper reference * @return the annotation of the field for the mapper reference
@ -102,9 +105,9 @@ public abstract class AnnotationBasedComponentModelProcessor implements ModelEle
protected abstract Annotation getMapperReferenceAnnotation(); 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 @Override
public int getPriority() { public int getPriority() {

View File

@ -18,6 +18,9 @@
*/ */
package org.mapstruct.ap.internal.processor; 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.Annotation;
import org.mapstruct.ap.internal.model.Mapper; import org.mapstruct.ap.internal.model.Mapper;
@ -36,8 +39,10 @@ public class CdiComponentProcessor extends AnnotationBasedComponentModelProcesso
} }
@Override @Override
protected Annotation getTypeAnnotation() { protected List<Annotation> getTypeAnnotations(Mapper mapper) {
return new Annotation( getTypeFactory().getType( "javax.enterprise.context.ApplicationScoped" ) ); return Collections.singletonList(
new Annotation( getTypeFactory().getType( "javax.enterprise.context.ApplicationScoped" ) )
);
} }
@Override @Override
@ -46,7 +51,7 @@ public class CdiComponentProcessor extends AnnotationBasedComponentModelProcesso
} }
@Override @Override
protected boolean shouldDecoratorBeRemoved() { protected boolean requiresGenerationOfDecoratorClass() {
return true; return false;
} }
} }

View File

@ -20,6 +20,8 @@ package org.mapstruct.ap.internal.processor;
import org.mapstruct.ap.internal.model.Annotation; import org.mapstruct.ap.internal.model.Annotation;
import org.mapstruct.ap.internal.model.Mapper; import org.mapstruct.ap.internal.model.Mapper;
import java.util.Collections;
import java.util.List;
/** /**
* A {@link ModelElementProcessor} which converts the given {@link Mapper} * A {@link ModelElementProcessor} which converts the given {@link Mapper}
@ -36,8 +38,8 @@ public class Jsr330ComponentProcessor extends AnnotationBasedComponentModelProce
} }
@Override @Override
protected Annotation getTypeAnnotation() { protected List<Annotation> getTypeAnnotations(Mapper mapper) {
return new Annotation( getTypeFactory().getType( "javax.inject.Named" ) ); return Collections.singletonList( new Annotation( getTypeFactory().getType( "javax.inject.Named" ) ) );
} }
@Override @Override
@ -46,7 +48,7 @@ public class Jsr330ComponentProcessor extends AnnotationBasedComponentModelProce
} }
@Override @Override
protected boolean shouldDecoratorBeRemoved() { protected boolean requiresGenerationOfDecoratorClass() {
return false; return true;
} }
} }

View File

@ -18,6 +18,10 @@
*/ */
package org.mapstruct.ap.internal.processor; 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.Annotation;
import org.mapstruct.ap.internal.model.Mapper; import org.mapstruct.ap.internal.model.Mapper;
@ -36,8 +40,19 @@ public class SpringComponentProcessor extends AnnotationBasedComponentModelProce
} }
@Override @Override
protected Annotation getTypeAnnotation() { protected List<Annotation> getTypeAnnotations(Mapper mapper) {
return new Annotation( getTypeFactory().getType( "org.springframework.stereotype.Component" ) ); List<Annotation> typeAnnotations = new ArrayList<Annotation>();
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 @Override
@ -46,7 +61,7 @@ public class SpringComponentProcessor extends AnnotationBasedComponentModelProce
} }
@Override @Override
protected boolean shouldDecoratorBeRemoved() { protected boolean requiresGenerationOfDecoratorClass() {
return true; return false;
} }
} }

View File

@ -18,4 +18,4 @@
limitations under the License. limitations under the License.
--> -->
@<@includeModel object=type/> @<@includeModel object=type/><#if (properties?size > 0) >(<#list properties as property>${property}<#if property_has_next>, </#if></#list>)</#if>