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 0f88cc81a..32f962b71 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 @@ -51,6 +51,8 @@ import org.mapstruct.ap.internal.util.accessor.Accessor; import org.mapstruct.ap.internal.util.accessor.ExecutableElementAccessor; import org.mapstruct.ap.spi.BuilderInfo; +import static org.mapstruct.ap.internal.util.Collections.first; + /** * Represents (a reference to) the type of a bean property, parameter etc. Types are managed per generated source file. * Each type corresponds to a {@link TypeMirror}, i.e. there are different instances for e.g. {@code Set} and @@ -578,23 +580,21 @@ public class Type extends ModelElement implements Comparable { if ( collectionProperty.isCollectionType ) { // 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 ).getTypeBound().getTypeMirror(); - // now, look for a method that - // 1) starts with add, - // 2) and has typeArg as one and only arg - List adderList = getAdders(); - for ( Accessor adder : adderList ) { - ExecutableElement executable = adder.getExecutable(); - if ( executable == null ) { - // it should not be null, but to be safe - continue; - } - VariableElement arg = executable.getParameters().get( 0 ); - if ( typeUtils.isSameType( arg.asType(), typeArg ) ) { - candidates.add( adder ); - } + TypeMirror typeArg = first( collectionProperty.determineTypeArguments( Iterable.class ) ).getTypeBound() + .getTypeMirror(); + // now, look for a method that + // 1) starts with add, + // 2) and has typeArg as one and only arg + List adderList = getAdders(); + for ( Accessor adder : adderList ) { + ExecutableElement executable = adder.getExecutable(); + if ( executable == null ) { + // it should not be null, but to be safe + continue; + } + VariableElement arg = executable.getParameters().get( 0 ); + if ( typeUtils.isSameType( arg.asType(), typeArg ) ) { + candidates.add( adder ); } } } diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1338/Issue1338Mapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1338/Issue1338Mapper.java new file mode 100644 index 000000000..ade7b14be --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1338/Issue1338Mapper.java @@ -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.ap.test.bugs._1338; + +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * @author Filip Hrisafov + */ +@Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED) +public interface Issue1338Mapper { + + Issue1338Mapper INSTANCE = Mappers.getMapper( Issue1338Mapper.class ); + + Target map(Source source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1338/Issue1338Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1338/Issue1338Test.java new file mode 100644 index 000000000..7b8d5ce8d --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1338/Issue1338Test.java @@ -0,0 +1,53 @@ +/** + * 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._1338; + +import java.util.Arrays; + +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; +import static org.assertj.core.api.Assertions.atIndex; + +/** + * @author Filip Hrisafov + */ +@RunWith(AnnotationProcessorTestRunner.class) +@IssueKey("1338") +@WithClasses({ + Issue1338Mapper.class, + Source.class, + Target.class +}) +public class Issue1338Test { + + @Test + public void shouldCorrectlyUseAdder() { + Target target = Issue1338Mapper.INSTANCE.map( new Source( Arrays.asList( "first", "second" ) ) ); + + assertThat( target ) + .extracting( "properties" ) + .contains( Arrays.asList( "first", "second" ), atIndex( 0 ) ); + + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1338/Source.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1338/Source.java new file mode 100644 index 000000000..5c8a6c84b --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1338/Source.java @@ -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.bugs._1338; + +import java.util.List; + +/** + * @author Filip Hrisafov + */ +public class Source { + + private final List properties; + + public Source(List properties) { + this.properties = properties; + } + + public List getProperties() { + return properties; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1338/Target.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1338/Target.java new file mode 100644 index 000000000..793541cbc --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1338/Target.java @@ -0,0 +1,44 @@ +/** + * 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._1338; + +import java.util.ArrayList; + +/** + * @author Filip Hrisafov + */ +public class Target { + + private StringList properties = new StringList(); + + public void addProperty(String property) { + properties.add( property ); + } + + public void setProperties(StringList properties) { + throw new IllegalStateException( "Setter is there just as a marker it should not be used" ); + } + + public static class StringList extends ArrayList { + + private StringList() { + // Constructor is private so we get a compile error if we try to instantiate it + } + } +}