#433 introduce resultType in @Mapping

This commit is contained in:
sjaakd 2015-01-26 20:19:04 +01:00
parent 490d454858
commit adcc89b184
26 changed files with 304 additions and 17 deletions

View File

@ -136,4 +136,11 @@ public @interface Mapping {
* @return the qualifiers * @return the qualifiers
*/ */
Class<? extends Annotation>[] qualifiedBy() default { }; Class<? extends Annotation>[] qualifiedBy() default { };
/**
* Specifies the result type of the mapping method to be used in case multiple mapping methods qualify.
*
* @return the resultType to select
*/
Class<?> resultType() default void.class;
} }

View File

@ -134,4 +134,11 @@ public @interface Mapping {
* @return the qualifiers * @return the qualifiers
*/ */
Class<? extends Annotation>[] qualifiedBy() default { }; Class<? extends Annotation>[] qualifiedBy() default { };
/**
* Specifies the result type of the mapping method to be used in case multiple mapping methods qualify.
*
* @return the resultType to select
*/
Class<?> resultType() default void.class;
} }

View File

@ -170,6 +170,7 @@ public class BeanMappingMethod extends MappingMethod {
.targetPropertyName( mapping.getTargetName() ) .targetPropertyName( mapping.getTargetName() )
.sourceReference( sourceRef ) .sourceReference( sourceRef )
.qualifiers( mapping.getQualifiers() ) .qualifiers( mapping.getQualifiers() )
.resultType( mapping.getResultType() )
.dateFormat( mapping.getDateFormat() ) .dateFormat( mapping.getDateFormat() )
.build(); .build();
handledTargets.add( mapping.getTargetName() ); handledTargets.add( mapping.getTargetName() );
@ -191,6 +192,7 @@ public class BeanMappingMethod extends MappingMethod {
.targetAccessor( targetProperty ) .targetAccessor( targetProperty )
.dateFormat( mapping.getDateFormat() ) .dateFormat( mapping.getDateFormat() )
.qualifiers( mapping.getQualifiers() ) .qualifiers( mapping.getQualifiers() )
.resultType( mapping.getResultType() )
.build(); .build();
handledTargets.add( mapping.getTargetName() ); handledTargets.add( mapping.getTargetName() );
} }
@ -277,6 +279,7 @@ public class BeanMappingMethod extends MappingMethod {
.targetPropertyName( targetProperty.getKey() ) .targetPropertyName( targetProperty.getKey() )
.sourceReference( sourceRef ) .sourceReference( sourceRef )
.qualifiers( mapping != null ? mapping.getQualifiers() : null ) .qualifiers( mapping != null ? mapping.getQualifiers() : null )
.resultType( mapping != null ? mapping.getResultType() : null )
.dateFormat( mapping != null ? mapping.getDateFormat() : null ) .dateFormat( mapping != null ? mapping.getDateFormat() : null )
.build(); .build();
@ -339,6 +342,7 @@ public class BeanMappingMethod extends MappingMethod {
.targetPropertyName( targetProperty.getKey() ) .targetPropertyName( targetProperty.getKey() )
.sourceReference( sourceRef ) .sourceReference( sourceRef )
.qualifiers( mapping != null ? mapping.getQualifiers() : null ) .qualifiers( mapping != null ? mapping.getQualifiers() : null )
.resultType( mapping != null ? mapping.getResultType() : null )
.dateFormat( mapping != null ? mapping.getDateFormat() : null ) .dateFormat( mapping != null ? mapping.getDateFormat() : null )
.build(); .build();

View File

@ -100,6 +100,7 @@ public class IterableMappingMethod extends MappingMethod {
null, // there is no targetPropertyName null, // there is no targetPropertyName
dateFormat, dateFormat,
qualifiers, qualifiers,
null, // resulttype does not seem to make sense
loopVariableName loopVariableName
); );

View File

@ -102,6 +102,7 @@ public class MapMappingMethod extends MappingMethod {
null, // there is no targetPropertyName null, // there is no targetPropertyName
keyDateFormat, keyDateFormat,
keyQualifiers, keyQualifiers,
null, // resulttype does not seem to make sense
"entry.getKey()" "entry.getKey()"
); );
@ -125,6 +126,7 @@ public class MapMappingMethod extends MappingMethod {
null, // there is no targetPropertyName null, // there is no targetPropertyName
valueDateFormat, valueDateFormat,
valueQualifiers, valueQualifiers,
null, // resulttype does not seem to make sense
"entry.getValue()" "entry.getValue()"
); );

View File

@ -80,6 +80,7 @@ public class MappingBuilderContext {
* @param targetPropertyName name of the target property * @param targetPropertyName name of the target property
* @param dateFormat used for formatting dates in build in methods that need context information * @param dateFormat used for formatting dates in build in methods that need context information
* @param qualifiers used for further select the appropriate mapping method based on class and name * @param qualifiers used for further select the appropriate mapping method based on class and name
* @param resultType used for further select the appropriate mapping method based on class and name
* @param sourceReference call to source type as string * @param sourceReference call to source type as string
* *
* @return an assignment to a method parameter, which can either be: * @return an assignment to a method parameter, which can either be:
@ -92,7 +93,7 @@ public class MappingBuilderContext {
*/ */
Assignment getTargetAssignment(Method mappingMethod, String mappedElement, Type sourceType, Type targetType, Assignment getTargetAssignment(Method mappingMethod, String mappedElement, Type sourceType, Type targetType,
String targetPropertyName, String dateFormat, List<TypeMirror> qualifiers, String targetPropertyName, String dateFormat, List<TypeMirror> qualifiers,
String sourceReference); TypeMirror resultType, String sourceReference);
/** /**
* returns a no arg factory method * returns a no arg factory method

View File

@ -70,6 +70,7 @@ public class PropertyMapping extends ModelElement {
private String targetPropertyName; private String targetPropertyName;
private String dateFormat; private String dateFormat;
private List<TypeMirror> qualifiers; private List<TypeMirror> qualifiers;
private TypeMirror resultType;
private SourceReference sourceReference; private SourceReference sourceReference;
public PropertyMappingBuilder mappingContext(MappingBuilderContext mappingContext) { public PropertyMappingBuilder mappingContext(MappingBuilderContext mappingContext) {
@ -102,6 +103,11 @@ public class PropertyMapping extends ModelElement {
return this; return this;
} }
public PropertyMappingBuilder resultType(TypeMirror resultType) {
this.resultType = resultType;
return this;
}
public PropertyMappingBuilder dateFormat(String dateFormat) { public PropertyMappingBuilder dateFormat(String dateFormat) {
this.dateFormat = dateFormat; this.dateFormat = dateFormat;
return this; return this;
@ -142,6 +148,7 @@ public class PropertyMapping extends ModelElement {
targetPropertyName, targetPropertyName,
dateFormat, dateFormat,
qualifiers, qualifiers,
resultType,
sourceRefStr sourceRefStr
); );
@ -450,6 +457,7 @@ public class PropertyMapping extends ModelElement {
private ExecutableElement targetAccessor; private ExecutableElement targetAccessor;
private String dateFormat; private String dateFormat;
private List<TypeMirror> qualifiers; private List<TypeMirror> qualifiers;
private TypeMirror resultType;
public ConstantMappingBuilder mappingContext(MappingBuilderContext mappingContext) { public ConstantMappingBuilder mappingContext(MappingBuilderContext mappingContext) {
this.ctx = mappingContext; this.ctx = mappingContext;
@ -481,6 +489,11 @@ public class PropertyMapping extends ModelElement {
return this; return this;
} }
public ConstantMappingBuilder resultType(TypeMirror resultType) {
this.resultType = resultType;
return this;
}
public PropertyMapping build() { public PropertyMapping build() {
// source // source
@ -506,6 +519,7 @@ public class PropertyMapping extends ModelElement {
targetPropertyName, targetPropertyName,
dateFormat, dateFormat,
qualifiers, qualifiers,
resultType,
constantExpression constantExpression
); );

View File

@ -55,6 +55,7 @@ public class Mapping {
private final String targetName; private final String targetName;
private final String dateFormat; private final String dateFormat;
private final List<TypeMirror> qualifiers; private final List<TypeMirror> qualifiers;
private final TypeMirror resultType;
private final boolean isIgnored; private final boolean isIgnored;
private final AnnotationMirror mirror; private final AnnotationMirror mirror;
@ -135,6 +136,9 @@ public class Mapping {
String expression = getExpression( mappingPrism, element, messager ); String expression = getExpression( mappingPrism, element, messager );
String dateFormat = mappingPrism.dateFormat().isEmpty() ? null : mappingPrism.dateFormat(); String dateFormat = mappingPrism.dateFormat().isEmpty() ? null : mappingPrism.dateFormat();
boolean resultTypeIsDefined = !TypeKind.VOID.equals( mappingPrism.resultType().getKind() );
TypeMirror resultType = resultTypeIsDefined ? mappingPrism.resultType() : null;
return new Mapping( return new Mapping(
source, source,
constant, constant,
@ -145,14 +149,17 @@ public class Mapping {
mappingPrism.ignore(), mappingPrism.ignore(),
mappingPrism.mirror, mappingPrism.mirror,
mappingPrism.values.source(), mappingPrism.values.source(),
mappingPrism.values.target() mappingPrism.values.target(),
resultType
); );
} }
@SuppressWarnings( "checkstyle:parameternumber" )
private Mapping(String sourceName, String constant, String javaExpression, String targetName, private Mapping(String sourceName, String constant, String javaExpression, String targetName,
String dateFormat, List<TypeMirror> qualifiers, String dateFormat, List<TypeMirror> qualifiers,
boolean isIgnored, AnnotationMirror mirror, boolean isIgnored, AnnotationMirror mirror,
AnnotationValue sourceAnnotationValue, AnnotationValue targetAnnotationValue) { AnnotationValue sourceAnnotationValue, AnnotationValue targetAnnotationValue,
TypeMirror resultType ) {
this.sourceName = sourceName; this.sourceName = sourceName;
this.constant = constant; this.constant = constant;
this.javaExpression = javaExpression; this.javaExpression = javaExpression;
@ -163,6 +170,7 @@ public class Mapping {
this.mirror = mirror; this.mirror = mirror;
this.sourceAnnotationValue = sourceAnnotationValue; this.sourceAnnotationValue = sourceAnnotationValue;
this.targetAnnotationValue = targetAnnotationValue; this.targetAnnotationValue = targetAnnotationValue;
this.resultType = resultType;
} }
private static String getExpression(MappingPrism mappingPrism, ExecutableElement element, Messager messager) { private static String getExpression(MappingPrism mappingPrism, ExecutableElement element, Messager messager) {
@ -257,6 +265,10 @@ public class Mapping {
return targetReference; return targetReference;
} }
public TypeMirror getResultType() {
return resultType;
}
private boolean hasPropertyInReverseMethod(String name, SourceMethod method) { private boolean hasPropertyInReverseMethod(String name, SourceMethod method) {
CollectionMappingStrategyPrism cms = method.getConfig().getCollectionMappingStrategy(); CollectionMappingStrategyPrism cms = method.getConfig().getCollectionMappingStrategy();
return method.getResultType().getTargetAccessors( cms ).containsKey( name ); return method.getResultType().getTargetAccessors( cms ).containsKey( name );
@ -303,7 +315,8 @@ public class Mapping {
isIgnored, isIgnored,
mirror, mirror,
sourceAnnotationValue, sourceAnnotationValue,
targetAnnotationValue targetAnnotationValue,
null
); );
reverse.init( method, messager, typeFactory ); reverse.init( method, messager, typeFactory );

View File

@ -170,7 +170,7 @@ public class SourceMethod implements Method {
} }
} }
//CHECKSTYLE:OFF @SuppressWarnings( "checkstyle:parameternumber" )
private SourceMethod( Type declaringMapper, ExecutableElement executable, List<Parameter> parameters, private SourceMethod( Type declaringMapper, ExecutableElement executable, List<Parameter> parameters,
Type returnType, List<Type> exceptionTypes, Map<String, List<Mapping>> mappings, Type returnType, List<Type> exceptionTypes, Map<String, List<Mapping>> mappings,
IterableMapping iterableMapping, MapMapping mapMapping, Types typeUtils, IterableMapping iterableMapping, MapMapping mapMapping, Types typeUtils,
@ -192,7 +192,6 @@ public class SourceMethod implements Method {
this.messager = messager; this.messager = messager;
this.config = config; this.config = config;
} }
//CHECKSTYLE:ON
private Parameter determineTargetParameter(Iterable<Parameter> parameters) { private Parameter determineTargetParameter(Iterable<Parameter> parameters) {
for ( Parameter parameter : parameters ) { for ( Parameter parameter : parameters ) {

View File

@ -124,9 +124,10 @@ public class MappingResolverImpl implements MappingResolver {
String targetPropertyName, String targetPropertyName,
String dateFormat, String dateFormat,
List<TypeMirror> qualifiers, List<TypeMirror> qualifiers,
TypeMirror resultType,
String sourceReference) { String sourceReference) {
SelectionCriteria criteria = new SelectionCriteria(qualifiers, targetPropertyName, null ); SelectionCriteria criteria = new SelectionCriteria(qualifiers, targetPropertyName, resultType );
ResolvingAttempt attempt = new ResolvingAttempt( ResolvingAttempt attempt = new ResolvingAttempt(
sourceModel, sourceModel,

View File

@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.mapstruct.ap.test.selection.inheritance; package org.mapstruct.ap.test.selection.resulttype;
/** /**
* *

View File

@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.mapstruct.ap.test.selection.inheritance; package org.mapstruct.ap.test.selection.resulttype;
/** /**
* *

View File

@ -0,0 +1,34 @@
/**
* Copyright 2012-2015 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.selection.resulttype;
/**
*
* @author Sjaak Derksen
*/
public class AppleFactory {
public Apple createApple() {
return new Apple( "apple" );
}
public GoldenDelicious createGoldenDelicious() {
return new GoldenDelicious( "GoldenDelicious" );
}
}

View File

@ -0,0 +1,37 @@
/**
* Copyright 2012-2015 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.selection.resulttype;
/**
*
* @author Sjaak Derksen
*/
public class AppleFamily {
private Apple apple;
public Apple getApple() {
return apple;
}
public void setApple(Apple apple) {
this.apple = apple;
}
}

View File

@ -0,0 +1,37 @@
/**
* Copyright 2012-2015 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.selection.resulttype;
/**
*
* @author Sjaak Derksen
*/
public class AppleFamilyDto {
private AppleDto apple;
public AppleDto getApple() {
return apple;
}
public void setApple(AppleDto apple) {
this.apple = apple;
}
}

View File

@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.mapstruct.ap.test.selection.inheritance; package org.mapstruct.ap.test.selection.resulttype;
/** /**
* *

View File

@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.mapstruct.ap.test.selection.inheritance; package org.mapstruct.ap.test.selection.resulttype;
/** /**
* *

View File

@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.mapstruct.ap.test.selection.inheritance; package org.mapstruct.ap.test.selection.resulttype;
/** /**
* *
@ -31,4 +31,5 @@ public class ConflictingFruitFactory {
public Banana createBanana() { public Banana createBanana() {
return new Banana( "banana" ); return new Banana( "banana" );
} }
} }

View File

@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.mapstruct.ap.test.selection.inheritance; package org.mapstruct.ap.test.selection.resulttype;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.Mapping; import org.mapstruct.Mapping;

View File

@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.mapstruct.ap.test.selection.inheritance; package org.mapstruct.ap.test.selection.resulttype;
/** /**
* *

View File

@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.mapstruct.ap.test.selection.inheritance; package org.mapstruct.ap.test.selection.resulttype;
/** /**
* *

View File

@ -0,0 +1,43 @@
/**
* Copyright 2012-2015 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.selection.resulttype;
import org.mapstruct.BeanMapping;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
/**
*
* @author Sjaak Derksen
*/
@Mapper(uses = AppleFactory.class)
public interface FruitFamilyMapper {
FruitFamilyMapper INSTANCE = Mappers.getMapper( FruitFamilyMapper.class );
@Mapping(target = "apple", resultType = GoldenDelicious.class)
AppleFamily map(AppleFamilyDto source);
GoldenDelicious mapToGoldenDelicious(AppleDto source);
@BeanMapping(resultType = Apple.class)
Apple mapToApple(AppleDto source);
}

View File

@ -0,0 +1,31 @@
/**
* Copyright 2012-2015 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.selection.resulttype;
/**
*
* @author Sjaak Derksen
*/
public class GoldenDelicious extends Apple {
public GoldenDelicious(String type) {
super( type );
}
}

View File

@ -0,0 +1,31 @@
/**
* Copyright 2012-2015 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.selection.resulttype;
/**
*
* @author Sjaak Derksen
*/
public class GoldenDeliciousDto extends AppleDto {
public GoldenDeliciousDto(String type) {
super( type );
}
}

View File

@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.mapstruct.ap.test.selection.inheritance; package org.mapstruct.ap.test.selection.resulttype;
import javax.tools.Diagnostic.Kind; import javax.tools.Diagnostic.Kind;
import static org.fest.assertions.Assertions.assertThat; import static org.fest.assertions.Assertions.assertThat;
@ -71,4 +71,28 @@ public class InheritanceSelectionTest {
} }
@Test
@IssueKey("433")
@WithClasses( {
FruitFamilyMapper.class,
GoldenDeliciousDto.class,
GoldenDelicious.class,
AppleFamily.class,
AppleFamilyDto.class,
AppleFactory.class,
Banana.class
} )
public void testShouldSelectResultTypeInCaseOfAmbiguity() {
AppleFamilyDto appleFamilyDto = new AppleFamilyDto();
appleFamilyDto.setApple( new AppleDto("AppleDto") );
AppleFamily result = FruitFamilyMapper.INSTANCE.map( appleFamilyDto );
assertThat( result ).isNotNull();
assertThat( result.getApple() ).isNotNull();
assertThat( result.getApple() ).isInstanceOf( GoldenDelicious.class );
assertThat( result.getApple().getType() ).isEqualTo( "AppleDto" );
}
} }

View File

@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.mapstruct.ap.test.selection.inheritance; package org.mapstruct.ap.test.selection.resulttype;
import org.mapstruct.BeanMapping; import org.mapstruct.BeanMapping;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;