diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/MethodReference.java b/processor/src/main/java/org/mapstruct/ap/internal/model/MethodReference.java index 003c196ab..be5c6ba80 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/MethodReference.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/MethodReference.java @@ -276,6 +276,15 @@ public class MethodReference extends ModelElement implements Assignment { return parameterBindings; } + public Type inferTypeWhenEnum( Type type ) { + if ( "java.lang.Enum".equals( type.getFullyQualifiedName() ) ) { + return type.getTypeParameters().get( 0 ); + } + else { + return type; + } + } + @Override public int hashCode() { final int prime = 31; diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/MethodMatcher.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/MethodMatcher.java index 91cc15106..74925d0c8 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/MethodMatcher.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/MethodMatcher.java @@ -263,14 +263,22 @@ public class MethodMatcher { // (type args are checked later). if ( p.getKind() == TypeKind.DECLARED ) { DeclaredType t1 = (DeclaredType) p; - if ( assignabilityMatches( t, t1 ) - && t.getTypeArguments().size() == t1.getTypeArguments().size() ) { - for ( int i = 0; i < t.getTypeArguments().size(); i++ ) { - if ( !visit( t.getTypeArguments().get( i ), t1.getTypeArguments().get( i ) ) ) { - return Boolean.FALSE; + if ( rawAssignabilityMatches( t, t1 ) ) { + if ( t.getTypeArguments().size() == t1.getTypeArguments().size() ) { + // compare type var side by side + for ( int i = 0; i < t.getTypeArguments().size(); i++ ) { + if ( !visit( t.getTypeArguments().get( i ), t1.getTypeArguments().get( i ) ) ) { + return Boolean.FALSE; + } } + return Boolean.TRUE; + } + else { + // return true (e.g. matching Enumeration with an enumeration E) + // but do not try to line up raw type arguments with types that do have arguments. + return assignability == Assignability.VISITED_ASSIGNABLE_TO ? + !t1.getTypeArguments().isEmpty() : !t.getTypeArguments().isEmpty(); } - return Boolean.TRUE; } else { return Boolean.FALSE; @@ -284,12 +292,12 @@ public class MethodMatcher { } } - private boolean assignabilityMatches(DeclaredType visited, DeclaredType param) { + private boolean rawAssignabilityMatches(DeclaredType t1, DeclaredType t2) { if ( assignability == Assignability.VISITED_ASSIGNABLE_TO ) { - return typeUtils.isAssignable( toRawType( visited ), toRawType( param ) ); + return typeUtils.isAssignable( toRawType( t1 ), toRawType( t2 ) ); } else { - return typeUtils.isAssignable( toRawType( param ), toRawType( visited ) ); + return typeUtils.isAssignable( toRawType( t2 ), toRawType( t1 ) ); } } @@ -302,7 +310,7 @@ public class MethodMatcher { if ( genericTypesMap.containsKey( t ) ) { // when already found, the same mapping should apply TypeMirror p1 = genericTypesMap.get( t ); - return typeUtils.isSameType( p, p1 ); + return typeUtils.isSubtype( p, p1 ); } else { // check if types are in bound diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/MethodReference.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/MethodReference.ftl index 8f4a31ddc..06c599c1c 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/MethodReference.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/MethodReference.ftl @@ -48,7 +48,7 @@ <#list parameterBindings as param> <#if param.targetType> <#-- a class is passed on for casting, see @TargetType --> - <@includeModel object=ext.targetType raw=true/>.class<#t> + <@includeModel object=inferTypeWhenEnum( ext.targetType ) raw=true/>.class<#t> <#elseif param.mappingTarget> ${ext.targetBeanName}<#if ext.targetReadAccessorName??>.${ext.targetReadAccessorName}<#t> <#elseif param.mappingContext> diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/BigDecimalWrapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/BigDecimalWrapper.java new file mode 100644 index 000000000..b68d22acd --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/BigDecimalWrapper.java @@ -0,0 +1,35 @@ +/** + * 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.bugs._1482; + +import java.math.BigDecimal; + +public class BigDecimalWrapper implements ValueWrapper { + + private final BigDecimal value; + + public BigDecimalWrapper(BigDecimal value) { + this.value = value; + } + + @Override + public BigDecimal getValue() { + return value; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/Issue1482Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/Issue1482Test.java new file mode 100644 index 000000000..48d72e4b0 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/Issue1482Test.java @@ -0,0 +1,75 @@ +/** + * 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.bugs._1482; + +import java.math.BigDecimal; + +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.assertj.core.api.Assertions.assertThat; + +@WithClasses({ + Source.class, + Source2.class, + Target.class, + SourceEnum.class, + SourceTargetMapper.class, + TargetSourceMapper.class, + BigDecimalWrapper.class, + ValueWrapper.class +}) +@IssueKey(value = "1482") +@RunWith(AnnotationProcessorTestRunner.class) +public class Issue1482Test { + + @Test + public void testForward() { + + Source source = new Source(); + source.setTest( SourceEnum.VAL1 ); + source.setWrapper( new BigDecimalWrapper( new BigDecimal( 5 ) ) ); + + Target target = SourceTargetMapper.INSTANCE.map( source ); + + assertThat( target ).isNotNull(); + assertThat( target.getTest() ).isEqualTo( "value1" ); + assertThat( target.getBigDecimal() ).isEqualTo( new BigDecimal( 5 ) ); + + } + + @Test + public void testReverse() { + + Target target = new Target(); + target.setBigDecimal( new BigDecimal( 5 ) ); + target.setTest( "VAL1" ); + + Source2 source2 = TargetSourceMapper.INSTANCE.map( target ); + + assertThat( source2 ).isNotNull(); + assertThat( source2.getTest() ).isEqualTo( SourceEnum.VAL1 ); + assertThat( source2.getWrapper().getValue() ).isEqualTo( new BigDecimal( 5 ) ); + + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/Source.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/Source.java new file mode 100644 index 000000000..82087751b --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/Source.java @@ -0,0 +1,41 @@ +/** + * 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.bugs._1482; + +public class Source { + + private SourceEnum test; + private BigDecimalWrapper wrapper; + + public SourceEnum getTest() { + return test; + } + + public void setTest(SourceEnum test) { + this.test = test; + } + + public BigDecimalWrapper getWrapper() { + return wrapper; + } + + public void setWrapper(BigDecimalWrapper wrapper) { + this.wrapper = wrapper; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/Source2.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/Source2.java new file mode 100644 index 000000000..3423132ce --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/Source2.java @@ -0,0 +1,43 @@ +/** + * 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.bugs._1482; + +import java.math.BigDecimal; + +public class Source2 { + + private Enum test; + private ValueWrapper wrapper; + + public Enum getTest() { + return test; + } + + public void setTest(Enum test) { + this.test = test; + } + + public ValueWrapper getWrapper() { + return wrapper; + } + + public void setWrapper(ValueWrapper wrapper) { + this.wrapper = wrapper; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/SourceEnum.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/SourceEnum.java new file mode 100644 index 000000000..58d065249 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/SourceEnum.java @@ -0,0 +1,35 @@ +/** + * 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.bugs._1482; + +public enum SourceEnum { + + VAL1( "value1" ), + VAL2( "value2" ); + + private final String val; + + SourceEnum(String val) { + this.val = val; + } + + public String toString() { + return val; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/SourceTargetMapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/SourceTargetMapper.java new file mode 100644 index 000000000..194587b15 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/SourceTargetMapper.java @@ -0,0 +1,40 @@ +/** + * 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.bugs._1482; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +@Mapper +public abstract class SourceTargetMapper { + + public static final SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class ); + + @Mapping( target = "bigDecimal", source = "wrapper" ) + abstract Target map(Source source); + + protected String map(Enum e) { + return e.toString(); + } + + protected T map(ValueWrapper in) { + return in.getValue(); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/Target.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/Target.java new file mode 100644 index 000000000..bb4d7a75c --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/Target.java @@ -0,0 +1,43 @@ +/** + * 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.bugs._1482; + +import java.math.BigDecimal; + +public class Target { + + private String test; + private BigDecimal bigDecimal; + + public String getTest() { + return test; + } + + public void setTest(String test) { + this.test = test; + } + + public BigDecimal getBigDecimal() { + return bigDecimal; + } + + public void setBigDecimal(BigDecimal bigDecimal) { + this.bigDecimal = bigDecimal; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/TargetSourceMapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/TargetSourceMapper.java new file mode 100644 index 000000000..3ad2af79d --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/TargetSourceMapper.java @@ -0,0 +1,50 @@ +/** + * 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.bugs._1482; + +import java.math.BigDecimal; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.TargetType; +import org.mapstruct.factory.Mappers; + +@Mapper +public abstract class TargetSourceMapper { + + public static final TargetSourceMapper INSTANCE = Mappers.getMapper( TargetSourceMapper.class ); + + @Mapping(target = "wrapper", source = "bigDecimal") + abstract Source2 map(Target target); + + protected > Enum map(String in, @TargetType Classclz ) { + if ( clz.isAssignableFrom( SourceEnum.class )) { + return (Enum) SourceEnum.valueOf( in ); + } + return null; + } + + protected ValueWrapper map(T in) { + if ( in instanceof BigDecimal ) { + return (ValueWrapper) new BigDecimalWrapper( (BigDecimal) in ); + + } + return null; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/ValueWrapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/ValueWrapper.java new file mode 100644 index 000000000..2ae62cee5 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1482/ValueWrapper.java @@ -0,0 +1,23 @@ +/** + * 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.bugs._1482; + +public interface ValueWrapper { + T getValue(); +}