From b5b0c04313355932aa6f53d8b66cad659e2328cc Mon Sep 17 00:00:00 2001 From: Cornelius Date: Thu, 29 Jun 2017 00:01:49 +0200 Subject: [PATCH] #1170 Fix wildcards in collection adder mappings --- .../tests/FullFeatureCompilationTest.java | 1 + .../model/assignment/AdderWrapper.java | 2 +- .../ap/internal/model/common/Type.java | 10 +- .../model/assignment/AdderWrapper.ftl | 2 +- .../bugs/_1170/AdderSourceTargetMapper.java | 40 ++++++ .../ap/test/bugs/_1170/AdderTest.java | 85 +++++++++++++ .../ap/test/bugs/_1170/PetMapper.java | 89 +++++++++++++ .../ap/test/bugs/_1170/_target/Target.java | 120 ++++++++++++++++++ .../ap/test/bugs/_1170/source/Source.java | 120 ++++++++++++++++++ 9 files changed, 463 insertions(+), 6 deletions(-) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1170/AdderSourceTargetMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1170/AdderTest.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1170/PetMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1170/_target/Target.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1170/source/Source.java diff --git a/integrationtest/src/test/java/org/mapstruct/itest/tests/FullFeatureCompilationTest.java b/integrationtest/src/test/java/org/mapstruct/itest/tests/FullFeatureCompilationTest.java index c89461dee..f53b673d9 100644 --- a/integrationtest/src/test/java/org/mapstruct/itest/tests/FullFeatureCompilationTest.java +++ b/integrationtest/src/test/java/org/mapstruct/itest/tests/FullFeatureCompilationTest.java @@ -69,6 +69,7 @@ public class FullFeatureCompilationTest { switch ( processorType ) { case ORACLE_JAVA_6: additionalExcludes.add( "org/mapstruct/ap/test/abstractclass/generics/*.java" ); + additionalExcludes.add( "org/mapstruct/ap/test/bugs/_1170/*.java" ); case ECLIPSE_JDT_JAVA_6: case ORACLE_JAVA_7: case ECLIPSE_JDT_JAVA_7: diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/AdderWrapper.java b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/AdderWrapper.java index 723ed044d..b41aa683c 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/AdderWrapper.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/AdderWrapper.java @@ -63,7 +63,7 @@ public class AdderWrapper extends AssignmentWrapper { public Set getImportTypes() { Set imported = new HashSet(); imported.addAll( super.getImportTypes() ); - imported.add( getSourceType().getTypeParameters().get( 0 ) ); + imported.add( getSourceType().getTypeParameters().get( 0 ).getTypeBound() ); return imported; } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java b/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java index 4a3350461..6fd311338 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java @@ -375,14 +375,16 @@ public class Type extends ModelElement implements Comparable { * * @return {@code true} if and only if this type is assignable to the given other type. */ - // TODO This doesn't yet take wild card types into account; e.g. ? extends Integer wouldn't be assignable to Number - // atm. + // TODO This doesn't yet take super wild card types into account; + // e.g. Number wouldn't be assignable to ? super Number atm. (is there any practical use case) public boolean isAssignableTo(Type other) { if ( equals( other ) ) { return true; } - return typeUtils.isAssignable( typeMirror, other.typeMirror ); + TypeMirror typeMirrorToMatch = isWildCardExtendsBound() ? getTypeBound().typeMirror : typeMirror; + + return typeUtils.isAssignable( typeMirrorToMatch, other.typeMirror ); } /** @@ -560,7 +562,7 @@ public class Type extends ModelElement implements Comparable { // this is a collection, so this can be done always if ( !collectionProperty.getTypeParameters().isEmpty() ) { // there's only one type arg to a collection - TypeMirror typeArg = collectionProperty.getTypeParameters().get( 0 ).getTypeMirror(); + TypeMirror typeArg = collectionProperty.getTypeParameters().get( 0 ).getTypeBound().getTypeMirror(); // now, look for a method that // 1) starts with add, // 2) and has typeArg as one and only arg diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/AdderWrapper.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/AdderWrapper.ftl index a3a781aab..c039f459c 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/AdderWrapper.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/AdderWrapper.ftl @@ -22,7 +22,7 @@ <#import "../macro/CommonMacros.ftl" as lib> <@lib.handleExceptions> if ( ${sourceReference} != null ) { - for ( <@includeModel object=sourceType.typeParameters[0]/> ${sourceLocalVarName} : ${sourceReference} ) { + for ( <@includeModel object=sourceType.typeParameters[0].typeBound/> ${sourceLocalVarName} : ${sourceReference} ) { ${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite><@lib.handleAssignment/>; } } diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1170/AdderSourceTargetMapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1170/AdderSourceTargetMapper.java new file mode 100644 index 000000000..a96629975 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1170/AdderSourceTargetMapper.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._1170; + +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.ap.test.bugs._1170._target.Target; +import org.mapstruct.ap.test.bugs._1170.source.Source; +import org.mapstruct.factory.Mappers; + +/** + * @author Cornelius Dirmeier + */ +@Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, + uses = { PetMapper.class }) +public interface AdderSourceTargetMapper { + + AdderSourceTargetMapper INSTANCE = Mappers.getMapper( AdderSourceTargetMapper.class ); + + Target toTarget(Source source); + + Source toSource(Target source); + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1170/AdderTest.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1170/AdderTest.java new file mode 100644 index 000000000..90b19f92e --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1170/AdderTest.java @@ -0,0 +1,85 @@ +/** + * 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._1170; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mapstruct.ap.test.bugs._1170._target.Target; +import org.mapstruct.ap.test.bugs._1170.source.Source; +import org.mapstruct.ap.testutil.IssueKey; +import org.mapstruct.ap.testutil.WithClasses; +import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner; + +/** + * @author Cornelius Dirmeier + */ +@WithClasses({ + Source.class, + Target.class, + AdderSourceTargetMapper.class, + PetMapper.class +}) +@RunWith(AnnotationProcessorTestRunner.class) +public class AdderTest { + + @IssueKey("1170") + @Test + public void testWildcardAdder() { + Source source = new Source(); + source.addWithoutWildcard( "mouse" ); + source.addWildcardInTarget( "mouse" ); + source.addWildcardInSource( "mouse" ); + source.addWildcardInBoth( "mouse" ); + source.addWildcardAdderToSetter( "mouse" ); + + Target target = AdderSourceTargetMapper.INSTANCE.toTarget( source ); + + assertThat( target ).isNotNull(); + assertThat( target.getWithoutWildcards() ).containsExactly( 2L ); + assertThat( target.getWildcardInSources() ).containsExactly( 2L ); + assertThat( target.getWildcardInTargets() ).containsExactly( 2L ); + assertThat( target.getWildcardInBoths() ).containsExactly( 2L ); + assertThat( target.getWildcardAdderToSetters() ).containsExactly( 2L ); + } + + @IssueKey("1170") + @Test + public void testWildcardAdderTargetToSource() { + Target target = new Target(); + target.addWithoutWildcard( 2L ); + target.addWildcardInTarget( 2L ); + target.getWildcardInSources().add( 2L ); + target.addWildcardInBoth( 2L ); + target.setWildcardAdderToSetters( Arrays.asList( 2L ) ); + + Source source = AdderSourceTargetMapper.INSTANCE.toSource( target ); + + assertThat( source ).isNotNull(); + assertThat( source.getWithoutWildcards() ).containsExactly( "mouse" ); + assertThat( source.getWildcardInSources() ).containsExactly( "mouse" ); + assertThat( source.getWildcardInTargets() ).containsExactly( "mouse" ); + assertThat( source.getWildcardInBoths() ).containsExactly( "mouse" ); + assertThat( source.getWildcardAdderToSetters() ).containsExactly( "mouse" ); + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1170/PetMapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1170/PetMapper.java new file mode 100644 index 000000000..847ec0424 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1170/PetMapper.java @@ -0,0 +1,89 @@ +/** + * 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._1170; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.mapstruct.Mapper; + +import com.google.common.collect.ImmutableMap; + +/** + * @author Cornelius Dirmeier + */ +@Mapper +public class PetMapper { + + private static final Map PETS_TO_TARGET = ImmutableMap.builder() + .put( "rabbit", 1L ) + .put( "mouse", 2L ).build(); + + private static final Map PETS_TO_SOURCE = ImmutableMap.builder() + .put( 1L, "rabbit" ) + .put( 2L, "mouse" ) + .put( 3L, "cat" ) + .put( 4L, "dog" ).build(); + + + /** + * method to be used when using an adder + * + * @param pet + * + * @return + * + * @throws DogException + */ + public Long toPet(String pet) { + return PETS_TO_TARGET.get( pet ); + } + + public String toSourcePets(Long pet) { + return PETS_TO_SOURCE.get( pet ); + } + + /** + * Method to be used when not using an adder + * + * @param pets + * + * @return + * + * @throws CatException + * @throws DogException + */ + public List toPets(List pets) { + List result = new ArrayList(); + for ( String pet : pets ) { + result.add( toPet( pet ) ); + } + return result; + } + + public List toSourcePets(List pets) { + List result = new ArrayList(); + for ( Long pet : pets ) { + result.add( PETS_TO_SOURCE.get( pet ) ); + } + return result; + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1170/_target/Target.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1170/_target/Target.java new file mode 100644 index 000000000..4e57ce7ff --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1170/_target/Target.java @@ -0,0 +1,120 @@ +/** + * 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._1170._target; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Cornelius Dirmeier + */ +public class Target { + + private List withoutWildcards = new ArrayList(); + + private List wildcardInSources = new ArrayList(); + + private List wildcardInTargets = new ArrayList(); + + private List wildcardInBoths = new ArrayList(); + + private List wildcardAdderToSetters = new ArrayList(); + + private List wildcardInSourcesAddAll = new ArrayList(); + + private List sameTypeWildcardInSources = new ArrayList(); + + private List sameTypeWildcardInTargets = new ArrayList(); + + private List sameTypeWildcardInBoths = new ArrayList(); + + public List getWithoutWildcards() { + return withoutWildcards; + } + + public Long addWithoutWildcard(Long pet) { + withoutWildcards.add( pet ); + return pet; + } + + public List getWildcardInSources() { + return wildcardInSources; + } + + public Long addWildcardInSource(Long pet) { + wildcardInSources.add( pet ); + return pet; + } + + public List getWildcardInTargets() { + return wildcardInTargets; + } + + public Long addWildcardInTarget(Long pet) { + wildcardInTargets.add( pet ); + return pet; + } + + public List getWildcardInBoths() { + return wildcardInTargets; + } + + public Long addWildcardInBoth(Long pet) { + wildcardInBoths.add( pet ); + return pet; + } + + public List getWildcardAdderToSetters() { + return wildcardAdderToSetters; + } + + public void setWildcardAdderToSetters(List pets) { + wildcardAdderToSetters = pets; + } + + public List getWildcardInSourcesAddAll() { + return wildcardInSourcesAddAll; + } + + public List getSameTypeWildcardInSources() { + return sameTypeWildcardInSources; + } + + public void addSameTypeWildcardInSource(BigDecimal pet) { + sameTypeWildcardInSources.add( pet ); + } + + public List getSameTypeWildcardInTargets() { + return sameTypeWildcardInTargets; + } + + public void addSameTypeWildcardInTarget(BigDecimal pet) { + sameTypeWildcardInTargets.add( pet ); + } + + public List getSameTypeWildcardInBoths() { + return sameTypeWildcardInBoths; + } + + public void addSameTypeWildcardInBoth(BigDecimal pet) { + sameTypeWildcardInBoths.add( pet ); + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1170/source/Source.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1170/source/Source.java new file mode 100644 index 000000000..07c5d671b --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1170/source/Source.java @@ -0,0 +1,120 @@ +/** + * 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._1170.source; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Cornelius Dirmeier + */ +public class Source { + + private List withoutWildcards = new ArrayList(); + + private List wildcardInSources = new ArrayList(); + + private List wildcardInTargets = new ArrayList(); + + private List wildcardInBoths = new ArrayList(); + + private List wildcardInSourcesAddAll = new ArrayList(); + + private List wildcardAdderToSetters = new ArrayList(); + + private List sameTypeWildcardInSources = new ArrayList(); + + private List sameTypeWildcardInTargets = new ArrayList(); + + private List sameTypeWildcardInBoths = new ArrayList(); + + public List getWithoutWildcards() { + return withoutWildcards; + } + + public void addWithoutWildcard(String pet) { + this.withoutWildcards.add( pet ); + } + + public List getWildcardInSources() { + return wildcardInSources; + } + + public void addWildcardInSource(String pet) { + wildcardInSources.add( pet ); + } + + public List getWildcardInTargets() { + return wildcardInTargets; + } + + public void addWildcardInTarget(String pet) { + wildcardInTargets.add( pet ); + } + + public List getWildcardInBoths() { + return wildcardInBoths; + } + + public void addWildcardInBoth(String pet) { + wildcardInBoths.add( pet ); + } + + public List getWildcardInSourcesAddAll() { + return wildcardInSourcesAddAll; + } + + public void addWildcardInSourcesAddAll(String pet) { + wildcardInSourcesAddAll.add( pet ); + } + + public List getWildcardAdderToSetters() { + return wildcardAdderToSetters; + } + + public void addWildcardAdderToSetter(String pet) { + wildcardAdderToSetters.add( pet ); + } + + public List getSameTypeWildcardInSources() { + return sameTypeWildcardInSources; + } + + public void addSameTypeWildcardInSource(BigDecimal pet) { + sameTypeWildcardInSources.add( pet ); + } + + public List getSameTypeWildcardInTargets() { + return sameTypeWildcardInTargets; + } + + public void addSameTypeWildcardInTarget(BigDecimal pet) { + sameTypeWildcardInTargets.add( pet ); + } + + public List getSameTypeWildcardInBoths() { + return sameTypeWildcardInBoths; + } + + public void addSameTypeWildcardInBoth(BigDecimal pet) { + sameTypeWildcardInBoths.add( pet ); + } + +}