#571 Add Constructor Injection for Annotation Based Component Model

- Allow configuring of injection strategy (Constructor / Field)
- Default injection strategy is Field
This commit is contained in:
Kevin 2017-07-30 20:53:45 +02:00 committed by Filip Hrisafov
parent e2391df04f
commit 0192bdaf83
41 changed files with 1584 additions and 39 deletions

View File

@ -0,0 +1,34 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct;
/**
* Strategy for handling injection. This is only used on annotated based component models such as CDI, Spring and
* JSR330.
*
* @author Kevin Grüneberg
*/
public enum InjectionStrategy {
/** Annotations are written on the field **/
FIELD,
/** Annotations are written on the constructor **/
CONSTRUCTOR
}

View File

@ -160,6 +160,16 @@ public @interface Mapper {
*/
NullValueCheckStrategy nullValueCheckStrategy() default ON_IMPLICIT_CONVERSION;
/**
* Determines whether to use field or constructor injection. This is only used on annotated based component models
* such as CDI, Spring and JSR 330.
*
* If no strategy is configured, {@link InjectionStrategy#FIELD} will be used as default.
*
* @return strategy how to inject
*/
InjectionStrategy injectionStrategy() default InjectionStrategy.FIELD;
/**
* If MapStruct could not find another mapping method or apply an automatic conversion it will try to generate a
* sub-mapping method between the two beans. If this property is set to {@code true} MapStruct will not try to

View File

@ -147,6 +147,18 @@ public @interface MapperConfig {
*/
NullValueCheckStrategy nullValueCheckStrategy() default ON_IMPLICIT_CONVERSION;
/**
* Determines whether to use field or constructor injection. This is only used on annotated based component models
* such as CDI, Spring and JSR 330.
*
* Can be overridden by the one on {@link Mapper}.
*
* If no strategy is configured, {@link InjectionStrategy#FIELD} will be used as default.
*
* @return strategy how to inject
*/
InjectionStrategy injectionStrategy() default InjectionStrategy.FIELD;
/**
* If MapStruct could not find another mapping method or apply an automatic conversion it will try to generate a
* sub-mapping method between the two beans. If this property is set to {@code true} MapStruct will not try to

View File

@ -0,0 +1,79 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.internal.model;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.mapstruct.ap.internal.model.common.ModelElement;
import org.mapstruct.ap.internal.model.common.Type;
/**
* Represents a constructor that is used for constructor injection.
*
* @author Kevin Grüneberg
*/
public class AnnotatedConstructor extends ModelElement implements Constructor {
private final String name;
private final List<AnnotationMapperReference> mapperReferences;
private final List<Annotation> annotations;
private final boolean publicEmptyConstructor;
public AnnotatedConstructor(String name, List<AnnotationMapperReference> mapperReferences,
List<Annotation> annotations, boolean publicEmptyConstructor) {
this.name = name;
this.mapperReferences = mapperReferences;
this.annotations = annotations;
this.publicEmptyConstructor = publicEmptyConstructor;
}
@Override
public Set<Type> getImportTypes() {
Set<Type> types = new HashSet<Type>();
for ( MapperReference mapperReference : mapperReferences ) {
types.addAll( mapperReference.getImportTypes() );
}
for ( Annotation annotation : annotations ) {
types.addAll( annotation.getImportTypes() );
}
return types;
}
@Override
public String getName() {
return name;
}
public List<AnnotationMapperReference> getMapperReferences() {
return mapperReferences;
}
public List<Annotation> getAnnotations() {
return annotations;
}
public boolean isPublicEmptyConstructor() {
return publicEmptyConstructor;
}
}

View File

@ -25,18 +25,28 @@ import java.util.Set;
import org.mapstruct.ap.internal.model.common.Type;
/**
* Mapper reference which is retrieved via Annotation-based dependency injection.
* Mapper reference which is retrieved via Annotation-based dependency injection.<br>
* The dependency injection may vary between field and constructor injection. Thus, it is possible to define, whether to
* include annotations on the field.
*
* @author Gunnar Morling
* @author Andreas Gudian
* @author Kevin Grüneberg
*/
public class AnnotationMapperReference extends MapperReference {
private final List<Annotation> annotations;
public AnnotationMapperReference(Type type, String variableName, List<Annotation> annotations, boolean isUsed) {
private final boolean fieldFinal;
private final boolean includeAnnotationsOnField;
public AnnotationMapperReference(Type type, String variableName, List<Annotation> annotations, boolean isUsed,
boolean fieldFinal, boolean includeAnnotationsOnField) {
super( type, variableName, isUsed );
this.annotations = annotations;
this.fieldFinal = fieldFinal;
this.includeAnnotationsOnField = includeAnnotationsOnField;
}
public List<Annotation> getAnnotations() {
@ -54,4 +64,22 @@ public class AnnotationMapperReference extends MapperReference {
return types;
}
public boolean isFieldFinal() {
return fieldFinal;
}
public boolean isIncludeAnnotationsOnField() {
return includeAnnotationsOnField;
}
public AnnotationMapperReference withNewAnnotations(List<Annotation> annotations) {
return new AnnotationMapperReference(
getType(),
getVariableName(),
annotations,
isUsed(),
isFieldFinal(),
isIncludeAnnotationsOnField() );
}
}

View File

@ -18,8 +18,12 @@
*/
package org.mapstruct.ap.internal.model;
import java.util.Set;
import org.mapstruct.ap.internal.model.common.Type;
/**
* Basic interface class that facilitates an empty constructor
* Basic interface class that facilitates an empty constructor.
*
* @author Sjaak Derksen
*/
@ -27,4 +31,6 @@ public interface Constructor {
String getName();
Set<Type> getImportTypes();
}

View File

@ -68,14 +68,9 @@ public abstract class GeneratedType extends ModelElement {
// CHECKSTYLE:OFF
protected GeneratedType(TypeFactory typeFactory, String packageName, String name, String superClassName,
String interfacePackage, String interfaceName,
List<MappingMethod> methods,
List<? extends Field> fields,
Options options,
VersionInformation versionInformation,
Accessibility accessibility,
SortedSet<Type> extraImportedTypes,
Constructor constructor ) {
String interfacePackage, String interfaceName, List<MappingMethod> methods,
List<? extends Field> fields, Options options, VersionInformation versionInformation,
Accessibility accessibility, SortedSet<Type> extraImportedTypes, Constructor constructor) {
this.packageName = packageName;
this.name = name;
this.superClassName = superClassName;
@ -169,6 +164,10 @@ public abstract class GeneratedType extends ModelElement {
return accessibility;
}
public void setConstructor(Constructor constructor) {
this.constructor = constructor;
}
@Override
public SortedSet<Type> getImportTypes() {
SortedSet<Type> importedTypes = new TreeSet<Type>();
@ -196,6 +195,12 @@ public abstract class GeneratedType extends ModelElement {
addIfImportRequired( importedTypes, extraImport );
}
if ( constructor != null ) {
for ( Type type : constructor.getImportTypes() ) {
addIfImportRequired( importedTypes, type );
}
}
return importedTypes;
}

View File

@ -18,11 +18,6 @@
*/
package org.mapstruct.ap.internal.model;
import static org.mapstruct.ap.internal.model.common.Assignment.AssignmentType.DIRECT;
import static org.mapstruct.ap.internal.prism.NullValueCheckStrategyPrism.ALWAYS;
import static org.mapstruct.ap.internal.util.Collections.first;
import static org.mapstruct.ap.internal.util.Collections.last;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -61,6 +56,11 @@ import org.mapstruct.ap.internal.util.Strings;
import org.mapstruct.ap.internal.util.ValueProvider;
import org.mapstruct.ap.internal.util.accessor.Accessor;
import static org.mapstruct.ap.internal.model.common.Assignment.AssignmentType.DIRECT;
import static org.mapstruct.ap.internal.prism.NullValueCheckStrategyPrism.ALWAYS;
import static org.mapstruct.ap.internal.util.Collections.first;
import static org.mapstruct.ap.internal.util.Collections.last;
/**
* Represents the mapping between a source and target property, e.g. from {@code String Source#foo} to
* {@code int Target#bar}. Name and type of source and target property can differ. If they have different types, the

View File

@ -0,0 +1,30 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.internal.prism;
/**
* Prism for the enum {@link org.mapstruct.InjectionStrategy}.
*
* @author Kevin Grüneberg
*/
public enum InjectionStrategyPrism {
FIELD,
CONSTRUCTOR;
}

View File

@ -20,27 +20,32 @@ package org.mapstruct.ap.internal.processor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import javax.lang.model.element.TypeElement;
import org.mapstruct.ap.internal.model.AnnotatedConstructor;
import org.mapstruct.ap.internal.model.Annotation;
import org.mapstruct.ap.internal.model.AnnotationMapperReference;
import org.mapstruct.ap.internal.model.Decorator;
import org.mapstruct.ap.internal.model.Field;
import org.mapstruct.ap.internal.model.Mapper;
import org.mapstruct.ap.internal.model.MapperReference;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.common.TypeFactory;
import org.mapstruct.ap.internal.prism.InjectionStrategyPrism;
import org.mapstruct.ap.internal.util.MapperConfiguration;
/**
* An {@link ModelElementProcessor} which converts the given {@link Mapper}
* object into an annotation based component model in case a matching model is selected as
* target component model for this mapper.
* An {@link ModelElementProcessor} which converts the given {@link Mapper} object into an annotation based component
* model in case a matching model is selected as target component model for this mapper.
*
* @author Gunnar Morling
* @author Andreas Gudian
* @author Kevin Grüneberg
*/
public abstract class AnnotationBasedComponentModelProcessor implements ModelElementProcessor<Mapper, Mapper> {
@ -50,8 +55,10 @@ public abstract class AnnotationBasedComponentModelProcessor implements ModelEle
public Mapper process(ProcessorContext context, TypeElement mapperTypeElement, Mapper mapper) {
this.typeFactory = context.getTypeFactory();
String componentModel = MapperConfiguration.getInstanceOn( mapperTypeElement )
.componentModel( context.getOptions() );
MapperConfiguration mapperConfiguration = MapperConfiguration.getInstanceOn( mapperTypeElement );
String componentModel = mapperConfiguration.componentModel( context.getOptions() );
InjectionStrategyPrism injectionStrategy = mapperConfiguration.getInjectionStrategy();
if ( !getComponentModelIdentifier().equalsIgnoreCase( componentModel ) ) {
return mapper;
@ -65,21 +72,26 @@ public abstract class AnnotationBasedComponentModelProcessor implements ModelEle
mapper.removeDecorator();
}
else if ( mapper.getDecorator() != null ) {
adjustDecorator( mapper );
adjustDecorator( mapper, injectionStrategy );
}
List<Annotation> annotations = getMapperReferenceAnnotations();
ListIterator<MapperReference> iterator = mapper.getReferencedMappers().listIterator();
while ( iterator.hasNext() ) {
MapperReference reference = iterator.next();
iterator.remove();
iterator.add( replacementMapperReference( reference, annotations ) );
iterator.add( replacementMapperReference( reference, annotations, injectionStrategy ) );
}
if ( injectionStrategy == InjectionStrategyPrism.CONSTRUCTOR ) {
buildConstructors( mapper );
}
return mapper;
}
protected void adjustDecorator(Mapper mapper) {
protected void adjustDecorator(Mapper mapper, InjectionStrategyPrism injectionStrategy) {
Decorator decorator = mapper.getDecorator();
for ( Annotation typeAnnotation : getDecoratorAnnotations() ) {
@ -88,17 +100,111 @@ public abstract class AnnotationBasedComponentModelProcessor implements ModelEle
decorator.removeConstructor();
List<Annotation> annotations = getDelegatorReferenceAnnotations( mapper );
List<Field> replacement = new ArrayList<Field>();
if ( !decorator.getMethods().isEmpty() ) {
for ( Field field : decorator.getFields() ) {
replacement.add( replacementMapperReference( field, annotations ) );
replacement.add( replacementMapperReference( field, annotations, injectionStrategy ) );
}
}
decorator.setFields( replacement );
}
private void buildConstructors(Mapper mapper) {
if ( !mapper.getReferencedMappers().isEmpty() ) {
AnnotatedConstructor annotatedConstructor = buildAnnotatedConstructorForMapper( mapper );
if ( !annotatedConstructor.getMapperReferences().isEmpty() ) {
mapper.setConstructor( annotatedConstructor );
}
}
Decorator decorator = mapper.getDecorator();
if ( decorator != null ) {
AnnotatedConstructor decoratorConstructor = buildAnnotatedConstructorForDecorator( decorator );
if ( !decoratorConstructor.getMapperReferences().isEmpty() ) {
decorator.setConstructor( decoratorConstructor );
}
}
}
private AnnotatedConstructor buildAnnotatedConstructorForMapper(Mapper mapper) {
List<AnnotationMapperReference> mapperReferencesForConstructor =
new ArrayList<AnnotationMapperReference>( mapper.getReferencedMappers().size() );
for ( MapperReference mapperReference : mapper.getReferencedMappers() ) {
mapperReferencesForConstructor.add( (AnnotationMapperReference) mapperReference );
}
List<Annotation> mapperReferenceAnnotations = getMapperReferenceAnnotations();
removeDuplicateAnnotations( mapperReferencesForConstructor, mapperReferenceAnnotations );
return new AnnotatedConstructor(
mapper.getName(),
mapperReferencesForConstructor,
mapperReferenceAnnotations,
additionalPublicEmptyConstructor() );
}
private AnnotatedConstructor buildAnnotatedConstructorForDecorator(Decorator decorator) {
List<AnnotationMapperReference> mapperReferencesForConstructor =
new ArrayList<AnnotationMapperReference>( decorator.getFields().size() );
for ( Field field : decorator.getFields() ) {
if ( field instanceof AnnotationMapperReference ) {
mapperReferencesForConstructor.add( (AnnotationMapperReference) field );
}
}
List<Annotation> mapperReferenceAnnotations = getMapperReferenceAnnotations();
removeDuplicateAnnotations( mapperReferencesForConstructor, mapperReferenceAnnotations );
return new AnnotatedConstructor(
decorator.getName(),
mapperReferencesForConstructor,
mapperReferenceAnnotations,
additionalPublicEmptyConstructor() );
}
/**
* Removes duplicate constructor parameter annotations. If an annotation is already present on the constructor, it
* does not have be defined on the constructor parameter, too. For example, for CDI, the javax.inject.Inject
* annotation is on the constructor and does not need to be on the constructor parameters.
*
* @param annotationMapperReferences annotations to annotate the constructor parameter with
* @param mapperReferenceAnnotations annotations to annotate the constructor with
*/
private void removeDuplicateAnnotations(List<AnnotationMapperReference> annotationMapperReferences,
List<Annotation> mapperReferenceAnnotations) {
ListIterator<AnnotationMapperReference> mapperReferenceIterator = annotationMapperReferences.listIterator();
Set<Type> mapperReferenceAnnotationsTypes = new HashSet<Type>();
for ( Annotation annotation : mapperReferenceAnnotations ) {
mapperReferenceAnnotationsTypes.add( annotation.getType() );
}
while ( mapperReferenceIterator.hasNext() ) {
AnnotationMapperReference annotationMapperReference = mapperReferenceIterator.next();
mapperReferenceIterator.remove();
List<Annotation> qualifiers = new ArrayList<Annotation>();
for ( Annotation annotation : annotationMapperReference.getAnnotations() ) {
if ( !mapperReferenceAnnotationsTypes.contains( annotation.getType() ) ) {
qualifiers.add( annotation );
}
}
mapperReferenceIterator.add( annotationMapperReference.withNewAnnotations( qualifiers ) );
}
}
protected boolean additionalPublicEmptyConstructor() {
return false;
}
protected List<Annotation> getDelegatorReferenceAnnotations(Mapper mapper) {
return Collections.emptyList();
}
@ -106,16 +212,23 @@ public abstract class AnnotationBasedComponentModelProcessor implements ModelEle
/**
* @param originalReference the reference to be replaced
* @param annotations the list of annotations
*
* @param injectionStrategyPrism strategy for injection
* @return the mapper reference replacing the original one
*/
protected MapperReference replacementMapperReference(Field originalReference, List<Annotation> annotations) {
protected MapperReference replacementMapperReference(Field originalReference, List<Annotation> annotations,
InjectionStrategyPrism injectionStrategyPrism) {
boolean finalField =
injectionStrategyPrism == InjectionStrategyPrism.CONSTRUCTOR && !additionalPublicEmptyConstructor();
boolean includeAnnotationsOnField = injectionStrategyPrism == InjectionStrategyPrism.FIELD;
return new AnnotationMapperReference(
originalReference.getType(),
originalReference.getVariableName(),
annotations,
originalReference.isUsed()
);
originalReference.isUsed(),
finalField,
includeAnnotationsOnField );
}
/**
@ -125,7 +238,6 @@ public abstract class AnnotationBasedComponentModelProcessor implements ModelEle
/**
* @param mapper the mapper
*
* @return the annotation(s) to be added at the mapper type implementation
*/
protected abstract List<Annotation> getTypeAnnotations(Mapper mapper);

View File

@ -55,4 +55,9 @@ public class CdiComponentProcessor extends AnnotationBasedComponentModelProcesso
protected boolean requiresGenerationOfDecoratorClass() {
return false;
}
@Override
protected boolean additionalPublicEmptyConstructor() {
return true;
}
}

View File

@ -29,6 +29,7 @@ import javax.lang.model.type.TypeMirror;
import org.mapstruct.ap.internal.option.Options;
import org.mapstruct.ap.internal.prism.CollectionMappingStrategyPrism;
import org.mapstruct.ap.internal.prism.InjectionStrategyPrism;
import org.mapstruct.ap.internal.prism.MapperConfigPrism;
import org.mapstruct.ap.internal.prism.MapperPrism;
import org.mapstruct.ap.internal.prism.MappingInheritanceStrategyPrism;
@ -155,6 +156,15 @@ public class MapperConfiguration {
}
}
public InjectionStrategyPrism getInjectionStrategy() {
if ( mapperConfigPrism != null && mapperPrism.values.injectionStrategy() == null ) {
return InjectionStrategyPrism.valueOf( mapperConfigPrism.injectionStrategy() );
}
else {
return InjectionStrategyPrism.valueOf( mapperPrism.injectionStrategy() );
}
}
public NullValueMappingStrategyPrism getNullValueMappingStrategy() {
if ( mapperConfigPrism != null && mapperPrism.values.nullValueMappingStrategy() == null ) {
return NullValueMappingStrategyPrism.valueOf( mapperConfigPrism.nullValueMappingStrategy() );

View File

@ -0,0 +1,35 @@
<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.AnnotatedConstructor" -->
<#--
Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
and/or other contributors as indicated by the @authors tag. See the
copyright.txt file in the distribution for a full listing of all
contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<#if publicEmptyConstructor>
public ${name}() {
}
</#if>
<#list annotations as annotation>
<#nt><@includeModel object=annotation/>
</#list>
public ${name}(<#list mapperReferences as mapperReference><#list mapperReference.annotations as annotation><@includeModel object=annotation/> </#list><@includeModel object=mapperReference.type/> ${mapperReference.variableName}<#if mapperReference_has_next>, </#if></#list>) {
<#list mapperReferences as mapperReference>
this.${mapperReference.variableName} = ${mapperReference.variableName};
</#list>
}

View File

@ -19,7 +19,9 @@
limitations under the License.
-->
<#list annotations as annotation>
<#nt><@includeModel object=annotation/>
</#list>
private <@includeModel object=type/> ${variableName};
<#if includeAnnotationsOnField>
<#list annotations as annotation>
<#nt><@includeModel object=annotation/>
</#list>
</#if>
private <#if fieldFinal>final </#if><@includeModel object=type/> ${variableName};

View File

@ -0,0 +1,38 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.decorator.spring.constructor;
import org.mapstruct.DecoratedWith;
import org.mapstruct.InjectionStrategy;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
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 = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR)
@DecoratedWith(PersonMapperDecorator.class)
public interface PersonMapper {
@Mapping( target = "name", ignore = true )
PersonDto personToPersonDto(Person person);
AddressDto addressToAddressDto(Address address);
}

View File

@ -0,0 +1,39 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.decorator.spring.constructor;
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;
public abstract class PersonMapperDecorator implements PersonMapper {
@Autowired
@Qualifier("delegate")
private PersonMapper delegate;
@Override
public PersonDto personToPersonDto(Person person) {
PersonDto dto = delegate.personToPersonDto( person );
dto.setName( person.getFirstName() + " " + person.getLastName() );
return dto;
}
}

View File

@ -0,0 +1,107 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.decorator.spring.constructor;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Calendar;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
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.WithClasses;
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
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;
/**
* Test for the application of decorators using component model spring.
*
* @author Andreas Gudian
*/
@WithClasses({
Person.class,
PersonDto.class,
Address.class,
AddressDto.class,
PersonMapper.class,
PersonMapperDecorator.class
})
@IssueKey("592")
@RunWith(AnnotationProcessorTestRunner.class)
@ComponentScan(basePackageClasses = SpringDecoratorTest.class)
@Configuration
public class SpringDecoratorTest {
@Autowired
private PersonMapper personMapper;
private ConfigurableApplicationContext context;
@Before
public void springUp() {
context = new AnnotationConfigApplicationContext( getClass() );
context.getAutowireCapableBeanFactory().autowireBean( this );
}
@After
public void springDown() {
if ( context != null ) {
context.close();
}
}
@Test
public void shouldInvokeDecoratorMethods() {
//given
Calendar birthday = Calendar.getInstance();
birthday.set( 1928, 4, 23 );
Person person = new Person( "Gary", "Crant", birthday.getTime(), new Address( "42 Ocean View Drive" ) );
//when
PersonDto personDto = personMapper.personToPersonDto( person );
//then
assertThat( personDto ).isNotNull();
assertThat( personDto.getName() ).isEqualTo( "Gary Crant" );
assertThat( personDto.getAddress() ).isNotNull();
assertThat( personDto.getAddress().getAddressLine() ).isEqualTo( "42 Ocean View Drive" );
}
@Test
public void shouldDelegateNonDecoratedMethodsToDefaultImplementation() {
//given
Address address = new Address( "42 Ocean View Drive" );
//when
AddressDto addressDto = personMapper.addressToAddressDto( address );
//then
assertThat( addressDto ).isNotNull();
assertThat( addressDto.getAddressLine() ).isEqualTo( "42 Ocean View Drive" );
}
}

View File

@ -16,9 +16,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.decorator.spring;
package org.mapstruct.ap.test.decorator.spring.field;
import org.mapstruct.DecoratedWith;
import org.mapstruct.InjectionStrategy;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.ap.test.decorator.Address;
@ -26,7 +27,7 @@ import org.mapstruct.ap.test.decorator.AddressDto;
import org.mapstruct.ap.test.decorator.Person;
import org.mapstruct.ap.test.decorator.PersonDto;
@Mapper(componentModel = "spring")
@Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.FIELD)
@DecoratedWith(PersonMapperDecorator.class)
public interface PersonMapper {

View File

@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.decorator.spring;
package org.mapstruct.ap.test.decorator.spring.field;
import org.mapstruct.ap.test.decorator.Person;
import org.mapstruct.ap.test.decorator.PersonDto;

View File

@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.decorator.spring;
package org.mapstruct.ap.test.decorator.spring.field;
import static org.assertj.core.api.Assertions.assertThat;

View File

@ -0,0 +1,29 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.injectionstrategy.jsr330.constructor;
import org.mapstruct.InjectionStrategy;
import org.mapstruct.MapperConfig;
/**
* @author Filip Hrisafov
*/
@MapperConfig(componentModel = "jsr330", injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface ConstructorJsr330Config {
}

View File

@ -0,0 +1,38 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.injectionstrategy.jsr330.constructor;
import org.mapstruct.InjectionStrategy;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.ap.test.injectionstrategy.shared.CustomerDto;
import org.mapstruct.ap.test.injectionstrategy.shared.CustomerEntity;
/**
* @author Kevin Grüneberg
*/
@Mapper( componentModel = "jsr330",
uses = GenderJsr330ConstructorMapper.class,
injectionStrategy = InjectionStrategy.CONSTRUCTOR )
public interface CustomerJsr330ConstructorMapper {
@Mapping(source = "gender", target = "gender")
CustomerDto asTarget(CustomerEntity customerEntity);
}

View File

@ -0,0 +1,38 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.injectionstrategy.jsr330.constructor;
import org.mapstruct.Mapper;
import org.mapstruct.ValueMapping;
import org.mapstruct.ValueMappings;
import org.mapstruct.ap.test.injectionstrategy.shared.Gender;
import org.mapstruct.ap.test.injectionstrategy.shared.GenderDto;
/**
* @author Kevin Grüneberg
*/
@Mapper(config = ConstructorJsr330Config.class)
public interface GenderJsr330ConstructorMapper {
@ValueMappings({
@ValueMapping(source = "MALE", target = "M"),
@ValueMapping(source = "FEMALE", target = "F")
})
GenderDto mapToDto(Gender gender);
}

View File

@ -0,0 +1,107 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.injectionstrategy.jsr330.constructor;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mapstruct.ap.test.injectionstrategy.shared.CustomerDto;
import org.mapstruct.ap.test.injectionstrategy.shared.CustomerEntity;
import org.mapstruct.ap.test.injectionstrategy.shared.Gender;
import org.mapstruct.ap.test.injectionstrategy.shared.GenderDto;
import org.mapstruct.ap.testutil.IssueKey;
import org.mapstruct.ap.testutil.WithClasses;
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
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 java.lang.System.lineSeparator;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test constructor injection for component model spring.
*
* @author Kevin Grüneberg
*/
@WithClasses({
CustomerDto.class,
CustomerEntity.class,
Gender.class,
GenderDto.class,
CustomerJsr330ConstructorMapper.class,
GenderJsr330ConstructorMapper.class,
ConstructorJsr330Config.class
})
@IssueKey("571")
@RunWith(AnnotationProcessorTestRunner.class)
@ComponentScan(basePackageClasses = CustomerJsr330ConstructorMapper.class)
@Configuration
public class Jsr330ConstructorMapperTest {
@Rule
public final GeneratedSource generatedSource = new GeneratedSource();
@Autowired
private CustomerJsr330ConstructorMapper customerMapper;
private ConfigurableApplicationContext context;
@Before
public void springUp() {
context = new AnnotationConfigApplicationContext( getClass() );
context.getAutowireCapableBeanFactory().autowireBean( this );
}
@After
public void springDown() {
if ( context != null ) {
context.close();
}
}
@Test
public void shouldConvertToTarget() {
// given
CustomerEntity customerEntity = new CustomerEntity();
customerEntity.setName( "Samuel" );
customerEntity.setGender( Gender.MALE );
// when
CustomerDto customerDto = customerMapper.asTarget( customerEntity );
// then
assertThat( customerDto ).isNotNull();
assertThat( customerDto.getName() ).isEqualTo( "Samuel" );
assertThat( customerDto.getGender() ).isEqualTo( GenderDto.M );
}
@Test
public void shouldHaveConstructorInjection() {
generatedSource.forMapper( CustomerJsr330ConstructorMapper.class )
.content()
.contains( "private final GenderJsr330ConstructorMapper" )
.contains( "@Inject" + lineSeparator() +
" public CustomerJsr330ConstructorMapperImpl(GenderJsr330ConstructorMapper" );
}
}

View File

@ -0,0 +1,33 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.injectionstrategy.jsr330.field;
import org.mapstruct.InjectionStrategy;
import org.mapstruct.Mapper;
import org.mapstruct.ap.test.injectionstrategy.shared.CustomerDto;
import org.mapstruct.ap.test.injectionstrategy.shared.CustomerEntity;
/**
* @author Kevin Grüneberg
*/
@Mapper(componentModel = "jsr330", uses = GenderJsr330FieldMapper.class, injectionStrategy = InjectionStrategy.FIELD)
public interface CustomerJsr330FieldMapper {
CustomerDto asTarget(CustomerEntity customerEntity);
}

View File

@ -0,0 +1,29 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.injectionstrategy.jsr330.field;
import org.mapstruct.InjectionStrategy;
import org.mapstruct.MapperConfig;
/**
* @author Filip Hrisafov
*/
@MapperConfig(componentModel = "jsr330", injectionStrategy = InjectionStrategy.FIELD)
public interface FieldJsr330Config {
}

View File

@ -0,0 +1,38 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.injectionstrategy.jsr330.field;
import org.mapstruct.Mapper;
import org.mapstruct.ValueMapping;
import org.mapstruct.ValueMappings;
import org.mapstruct.ap.test.injectionstrategy.shared.Gender;
import org.mapstruct.ap.test.injectionstrategy.shared.GenderDto;
/**
* @author Kevin Grüneberg
*/
@Mapper(config = FieldJsr330Config.class)
public interface GenderJsr330FieldMapper {
@ValueMappings({
@ValueMapping(source = "MALE", target = "M"),
@ValueMapping(source = "FEMALE", target = "F")
})
GenderDto mapToDto(Gender gender);
}

View File

@ -0,0 +1,109 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.injectionstrategy.jsr330.field;
import javax.inject.Inject;
import javax.inject.Named;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mapstruct.ap.test.injectionstrategy.shared.CustomerDto;
import org.mapstruct.ap.test.injectionstrategy.shared.CustomerEntity;
import org.mapstruct.ap.test.injectionstrategy.shared.Gender;
import org.mapstruct.ap.test.injectionstrategy.shared.GenderDto;
import org.mapstruct.ap.testutil.IssueKey;
import org.mapstruct.ap.testutil.WithClasses;
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
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 java.lang.System.lineSeparator;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test field injection for component model spring.
*
* @author Kevin Grüneberg
*/
@WithClasses({
CustomerDto.class,
CustomerEntity.class,
Gender.class,
GenderDto.class,
CustomerJsr330FieldMapper.class,
GenderJsr330FieldMapper.class,
FieldJsr330Config.class
})
@IssueKey("571")
@RunWith(AnnotationProcessorTestRunner.class)
@ComponentScan(basePackageClasses = CustomerJsr330FieldMapper.class)
@Configuration
public class Jsr330FieldMapperTest {
@Rule
public final GeneratedSource generatedSource = new GeneratedSource();
@Inject
@Named
private CustomerJsr330FieldMapper customerMapper;
private ConfigurableApplicationContext context;
@Before
public void springUp() {
context = new AnnotationConfigApplicationContext( getClass() );
context.getAutowireCapableBeanFactory().autowireBean( this );
}
@After
public void springDown() {
if ( context != null ) {
context.close();
}
}
@Test
public void shouldConvertToTarget() {
// given
CustomerEntity customerEntity = new CustomerEntity();
customerEntity.setName( "Samuel" );
customerEntity.setGender( Gender.MALE );
// when
CustomerDto customerDto = customerMapper.asTarget( customerEntity );
// then
assertThat( customerDto ).isNotNull();
assertThat( customerDto.getName() ).isEqualTo( "Samuel" );
assertThat( customerDto.getGender() ).isEqualTo( GenderDto.M );
}
@Test
public void shouldHaveFieldInjection() {
generatedSource.forMapper( CustomerJsr330FieldMapper.class )
.content()
.contains( "@Inject" + lineSeparator() + " private GenderJsr330FieldMapper" )
.doesNotContain( "public CustomerJsr330FieldMapperImpl(" );
}
}

View File

@ -0,0 +1,45 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.injectionstrategy.shared;
/**
* @author Kevin Grüneberg
*/
public class CustomerDto {
private GenderDto gender;
private String name;
public GenderDto getGender() {
return gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setGender(GenderDto gender) {
this.gender = gender;
}
}

View File

@ -0,0 +1,45 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.injectionstrategy.shared;
/**
* @author Kevin Grüneberg
*/
public class CustomerEntity {
private Gender gender;
private String name;
public Gender getGender() {
return gender;
}
public void setGender(Gender gender) {
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,28 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.injectionstrategy.shared;
/**
* @author Kevin Grüneberg
*/
public enum Gender {
MALE, FEMALE
}

View File

@ -0,0 +1,28 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.injectionstrategy.shared;
/**
* @author Kevin Grüneberg
*/
public enum GenderDto {
M, F
}

View File

@ -0,0 +1,29 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.injectionstrategy.spring.constructor;
import org.mapstruct.InjectionStrategy;
import org.mapstruct.MapperConfig;
/**
* @author Filip Hrisafov
*/
@MapperConfig(componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface ConstructorSpringConfig {
}

View File

@ -0,0 +1,37 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.injectionstrategy.spring.constructor;
import org.mapstruct.InjectionStrategy;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.ap.test.injectionstrategy.shared.CustomerDto;
import org.mapstruct.ap.test.injectionstrategy.shared.CustomerEntity;
/**
* @author Kevin Grüneberg
*/
@Mapper( componentModel = "spring",
uses = GenderSpringConstructorMapper.class,
injectionStrategy = InjectionStrategy.CONSTRUCTOR )
public interface CustomerSpringConstructorMapper {
@Mapping( source = "gender", target = "gender" )
CustomerDto asTarget(CustomerEntity customerEntity);
}

View File

@ -0,0 +1,38 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.injectionstrategy.spring.constructor;
import org.mapstruct.Mapper;
import org.mapstruct.ValueMapping;
import org.mapstruct.ValueMappings;
import org.mapstruct.ap.test.injectionstrategy.shared.Gender;
import org.mapstruct.ap.test.injectionstrategy.shared.GenderDto;
/**
* @author Kevin Grüneberg
*/
@Mapper(config = ConstructorSpringConfig.class)
public interface GenderSpringConstructorMapper {
@ValueMappings({
@ValueMapping(source = "MALE", target = "M"),
@ValueMapping(source = "FEMALE", target = "F")
})
GenderDto mapToDto(Gender gender);
}

View File

@ -0,0 +1,107 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.injectionstrategy.spring.constructor;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mapstruct.ap.test.injectionstrategy.shared.CustomerDto;
import org.mapstruct.ap.test.injectionstrategy.shared.CustomerEntity;
import org.mapstruct.ap.test.injectionstrategy.shared.Gender;
import org.mapstruct.ap.test.injectionstrategy.shared.GenderDto;
import org.mapstruct.ap.testutil.IssueKey;
import org.mapstruct.ap.testutil.WithClasses;
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
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 java.lang.System.lineSeparator;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test constructor injection for component model spring.
*
* @author Kevin Grüneberg
*/
@WithClasses( {
CustomerDto.class,
CustomerEntity.class,
Gender.class,
GenderDto.class,
CustomerSpringConstructorMapper.class,
GenderSpringConstructorMapper.class,
ConstructorSpringConfig.class
} )
@IssueKey( "571" )
@RunWith(AnnotationProcessorTestRunner.class)
@ComponentScan(basePackageClasses = CustomerSpringConstructorMapper.class)
@Configuration
public class SpringConstructorMapperTest {
@Rule
public final GeneratedSource generatedSource = new GeneratedSource();
@Autowired
private CustomerSpringConstructorMapper customerMapper;
private ConfigurableApplicationContext context;
@Before
public void springUp() {
context = new AnnotationConfigApplicationContext( getClass() );
context.getAutowireCapableBeanFactory().autowireBean( this );
}
@After
public void springDown() {
if ( context != null ) {
context.close();
}
}
@Test
public void shouldConvertToTarget() {
// given
CustomerEntity customerEntity = new CustomerEntity();
customerEntity.setName( "Samuel" );
customerEntity.setGender( Gender.MALE );
// when
CustomerDto customerDto = customerMapper.asTarget( customerEntity );
// then
assertThat( customerDto ).isNotNull();
assertThat( customerDto.getName() ).isEqualTo( "Samuel" );
assertThat( customerDto.getGender() ).isEqualTo( GenderDto.M );
}
@Test
public void shouldHaveConstructorInjection() {
generatedSource.forMapper( CustomerSpringConstructorMapper.class )
.content()
.contains( "private final GenderSpringConstructorMapper" )
.contains( "@Autowired" + lineSeparator() +
" public CustomerSpringConstructorMapperImpl(GenderSpringConstructorMapper" );
}
}

View File

@ -0,0 +1,33 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.injectionstrategy.spring.field;
import org.mapstruct.InjectionStrategy;
import org.mapstruct.Mapper;
import org.mapstruct.ap.test.injectionstrategy.shared.CustomerDto;
import org.mapstruct.ap.test.injectionstrategy.shared.CustomerEntity;
/**
* @author Kevin Grüneberg
*/
@Mapper(componentModel = "spring", uses = GenderSpringFieldMapper.class, injectionStrategy = InjectionStrategy.FIELD)
public interface CustomerSpringFieldMapper {
CustomerDto asTarget(CustomerEntity customerEntity);
}

View File

@ -0,0 +1,29 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.injectionstrategy.spring.field;
import org.mapstruct.InjectionStrategy;
import org.mapstruct.MapperConfig;
/**
* @author Filip Hrisafov
*/
@MapperConfig(componentModel = "spring", injectionStrategy = InjectionStrategy.FIELD)
public interface FieldSpringConfig {
}

View File

@ -0,0 +1,38 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.injectionstrategy.spring.field;
import org.mapstruct.Mapper;
import org.mapstruct.ValueMapping;
import org.mapstruct.ValueMappings;
import org.mapstruct.ap.test.injectionstrategy.shared.Gender;
import org.mapstruct.ap.test.injectionstrategy.shared.GenderDto;
/**
* @author Kevin Grüneberg
*/
@Mapper(config = FieldSpringConfig.class)
public interface GenderSpringFieldMapper {
@ValueMappings({
@ValueMapping(source = "MALE", target = "M"),
@ValueMapping(source = "FEMALE", target = "F")
})
GenderDto mapToDto(Gender gender);
}

View File

@ -0,0 +1,106 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.injectionstrategy.spring.field;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mapstruct.ap.test.injectionstrategy.shared.CustomerDto;
import org.mapstruct.ap.test.injectionstrategy.shared.CustomerEntity;
import org.mapstruct.ap.test.injectionstrategy.shared.Gender;
import org.mapstruct.ap.test.injectionstrategy.shared.GenderDto;
import org.mapstruct.ap.testutil.IssueKey;
import org.mapstruct.ap.testutil.WithClasses;
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
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 java.lang.System.lineSeparator;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test field injection for component model spring.
*
* @author Kevin Grüneberg
*/
@WithClasses({
CustomerDto.class,
CustomerEntity.class,
Gender.class,
GenderDto.class,
CustomerSpringFieldMapper.class,
GenderSpringFieldMapper.class,
FieldSpringConfig.class
})
@IssueKey("571")
@RunWith(AnnotationProcessorTestRunner.class)
@ComponentScan(basePackageClasses = CustomerSpringFieldMapper.class)
@Configuration
public class SpringFieldMapperTest {
@Rule
public final GeneratedSource generatedSource = new GeneratedSource();
@Autowired
private CustomerSpringFieldMapper customerMapper;
private ConfigurableApplicationContext context;
@Before
public void springUp() {
context = new AnnotationConfigApplicationContext( getClass() );
context.getAutowireCapableBeanFactory().autowireBean( this );
}
@After
public void springDown() {
if ( context != null ) {
context.close();
}
}
@Test
public void shouldConvertToTarget() {
// given
CustomerEntity customerEntity = new CustomerEntity();
customerEntity.setName( "Samuel" );
customerEntity.setGender( Gender.MALE );
// when
CustomerDto customerDto = customerMapper.asTarget( customerEntity );
// then
assertThat( customerDto ).isNotNull();
assertThat( customerDto.getName() ).isEqualTo( "Samuel" );
assertThat( customerDto.getGender() ).isEqualTo( GenderDto.M );
}
@Test
public void shouldHaveFieldInjection() {
generatedSource.forMapper( CustomerSpringFieldMapper.class )
.content()
.contains( "@Autowired" + lineSeparator() + " private GenderSpringFieldMapper" )
.doesNotContain( "public CustomerSpringFieldMapperImpl(" );
}
}

View File

@ -25,11 +25,13 @@ import java.util.List;
import org.junit.Test;
import org.mapstruct.CollectionMappingStrategy;
import org.mapstruct.InjectionStrategy;
import org.mapstruct.MappingInheritanceStrategy;
import org.mapstruct.NullValueCheckStrategy;
import org.mapstruct.NullValueMappingStrategy;
import org.mapstruct.ReportingPolicy;
import org.mapstruct.ap.internal.prism.CollectionMappingStrategyPrism;
import org.mapstruct.ap.internal.prism.InjectionStrategyPrism;
import org.mapstruct.ap.internal.prism.MappingInheritanceStrategyPrism;
import org.mapstruct.ap.internal.prism.NullValueCheckStrategyPrism;
import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism;
@ -71,6 +73,12 @@ public class EnumPrismsTest {
namesOf( ReportingPolicyPrism.values() ) );
}
@Test
public void injectionStrategyPrismIsCorrect() {
assertThat( namesOf( InjectionStrategy.values() ) ).isEqualTo(
namesOf( InjectionStrategyPrism.values() ) );
}
private static List<String> namesOf(Enum<?>[] values) {
List<String> names = new ArrayList<String>( values.length );