diff --git a/processor/src/main/java/org/mapstruct/ap/processor/creation/MappingResolverImpl.java b/processor/src/main/java/org/mapstruct/ap/processor/creation/MappingResolverImpl.java index fc175c47c..9f3bccb28 100644 --- a/processor/src/main/java/org/mapstruct/ap/processor/creation/MappingResolverImpl.java +++ b/processor/src/main/java/org/mapstruct/ap/processor/creation/MappingResolverImpl.java @@ -178,10 +178,9 @@ public class MappingResolverImpl implements MappingResolver { private Assignment getTargetAssignment(Type sourceType, Type targetType) { // first simple mapping method - Assignment referencedMethod = resolveViaMethod( sourceType, targetType ); + Assignment referencedMethod = resolveViaMethod( sourceType, targetType, false ); if ( referencedMethod != null ) { referencedMethod.setAssignment( AssignmentFactory.createSimple( sourceReference ) ); - usedVirtualMappings.addAll( virtualMethodCandidates ); return referencedMethod; } @@ -198,21 +197,29 @@ public class MappingResolverImpl implements MappingResolver { return conversion; } - // 2 step method, first: method(method(souurce)) + // check for a built-in method + Assignment builtInMethod = resolveViaBuiltInMethod( sourceType, targetType ); + if ( builtInMethod != null ) { + builtInMethod.setAssignment( AssignmentFactory.createSimple( sourceReference ) ); + usedVirtualMappings.addAll( virtualMethodCandidates ); + return builtInMethod; + } + + // 2 step method, first: method(method(source)) referencedMethod = resolveViaMethodAndMethod( sourceType, targetType ); if ( referencedMethod != null ) { usedVirtualMappings.addAll( virtualMethodCandidates ); return referencedMethod; } - // 2 step method, then: method(conversion(souurce)) + // 2 step method, then: method(conversion(source)) referencedMethod = resolveViaConversionAndMethod( sourceType, targetType ); if ( referencedMethod != null ) { usedVirtualMappings.addAll( virtualMethodCandidates ); return referencedMethod; } - // 2 step method, finally: conversion(method(souurce)) + // 2 step method, finally: conversion(method(source)) conversion = resolveViaMethodAndConversion( sourceType, targetType ); if ( conversion != null ) { usedVirtualMappings.addAll( virtualMethodCandidates ); @@ -239,7 +246,7 @@ public class MappingResolverImpl implements MappingResolver { * Returns a reference to a method mapping the given source type to the given target type, if such a method * exists. */ - private Assignment resolveViaMethod(Type sourceType, Type targetType) { + private Assignment resolveViaMethod(Type sourceType, Type targetType, boolean considerBuiltInMethods) { // first try to find a matching source method SourceMethod matchingSourceMethod = getBestMatch( methods, sourceType, targetType ); @@ -248,14 +255,20 @@ public class MappingResolverImpl implements MappingResolver { return getMappingMethodReference( matchingSourceMethod, targetType ); } - // then a matching built-in method + if ( considerBuiltInMethods ) { + return resolveViaBuiltInMethod( sourceType, targetType ); + } + + return null; + } + + private Assignment resolveViaBuiltInMethod(Type sourceType, Type targetType) { BuiltInMethod matchingBuiltInMethod = getBestMatch( builtInMethods.getBuiltInMethods(), sourceType, targetType ); if ( matchingBuiltInMethod != null ) { virtualMethodCandidates.add( new VirtualMappingMethod( matchingBuiltInMethod ) ); - ConversionContext ctx = - new DefaultConversionContext( typeFactory, targetType, dateFormat ); + ConversionContext ctx = new DefaultConversionContext( typeFactory, targetType, dateFormat ); Assignment methodReference = AssignmentFactory.createMethodReference( matchingBuiltInMethod, ctx ); methodReference.setAssignment( AssignmentFactory.createSimple( sourceReference ) ); return methodReference; @@ -291,12 +304,14 @@ public class MappingResolverImpl implements MappingResolver { if ( methodYCandidate.getSourceParameters().size() == 1 ) { methodRefY = resolveViaMethod( methodYCandidate.getSourceParameters().get( 0 ).getType(), - targetType + targetType, + true ); if ( methodRefY != null ) { Assignment methodRefX = resolveViaMethod( sourceType, - methodYCandidate.getSourceParameters().get( 0 ).getType() + methodYCandidate.getSourceParameters().get( 0 ).getType(), + true ); if ( methodRefX != null ) { methodRefY.setAssignment( methodRefX ); @@ -333,7 +348,8 @@ public class MappingResolverImpl implements MappingResolver { if ( methodYCandidate.getSourceParameters().size() == 1 ) { methodRefY = resolveViaMethod( methodYCandidate.getSourceParameters().get( 0 ).getType(), - targetType + targetType, + true ); if ( methodRefY != null ) { Assignment conversionXRef = resolveViaConversion( @@ -376,7 +392,8 @@ public class MappingResolverImpl implements MappingResolver { if ( methodXCandidate.getSourceParameters().size() == 1 ) { Assignment methodRefX = resolveViaMethod( sourceType, - methodXCandidate.getReturnType() + methodXCandidate.getReturnType(), + true ); if ( methodRefX != null ) { conversionYRef = resolveViaConversion( methodXCandidate.getReturnType(), targetType ); diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/string/Source.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/string/Source.java index bf5b86a68..08913cbde 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/conversion/string/Source.java +++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/string/Source.java @@ -36,6 +36,7 @@ public class Source { private Boolean boolBool; private char c; private Character cc; + private Object object; public byte getB() { return b; @@ -164,4 +165,12 @@ public class Source { public void setCc(Character cc) { this.cc = cc; } + + public Object getObject() { + return object; + } + + public void setObject(Object object) { + this.object = object; + } } diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/string/SourceTargetMapper.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/string/SourceTargetMapper.java index f12753421..02448cc7c 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/conversion/string/SourceTargetMapper.java +++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/string/SourceTargetMapper.java @@ -19,6 +19,7 @@ package org.mapstruct.ap.test.conversion.string; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; @Mapper @@ -26,6 +27,7 @@ public interface SourceTargetMapper { SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class ); + @Mapping( source = "object", ignore = true ) Target sourceToTarget(Source source); Source targetToSource(Target target); diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/string/StringConversionTest.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/string/StringConversionTest.java index 3b95fd899..4573af620 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/conversion/string/StringConversionTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/string/StringConversionTest.java @@ -18,13 +18,14 @@ */ package org.mapstruct.ap.test.conversion.string; -import static org.fest.assertions.Assertions.assertThat; - import org.junit.Test; import org.junit.runner.RunWith; +import org.mapstruct.ap.testutil.IssueKey; import org.mapstruct.ap.testutil.WithClasses; import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner; +import static org.fest.assertions.Assertions.assertThat; + @WithClasses({ Source.class, Target.class, @@ -33,6 +34,8 @@ import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner; @RunWith(AnnotationProcessorTestRunner.class) public class StringConversionTest { + private static final String STRING_CONTANT = "String contant"; + @Test public void shouldApplyStringConversions() { Source source = new Source(); @@ -114,4 +117,16 @@ public class StringConversionTest { assertThat( source.getC() ).isEqualTo( 'G' ); assertThat( source.getCc() ).isEqualTo( 'H' ); } + + @Test + @IssueKey( "328" ) + public void stringShouldBeMappedToObjectByReference() { + Target target = new Target(); + target.setObject( STRING_CONTANT ); + + Source source = SourceTargetMapper.INSTANCE.targetToSource( target ); + + // no conversion, no built-in method + assertThat( source.getObject() ).isSameAs( STRING_CONTANT ); + } } diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/string/Target.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/string/Target.java index 4373b0e2d..0d01af66c 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/conversion/string/Target.java +++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/string/Target.java @@ -36,6 +36,7 @@ public class Target { private String boolBool; private String c; private String cc; + private String object; public String getB() { return b; @@ -165,4 +166,11 @@ public class Target { this.cc = cc; } + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } }