From 15133d5a0fa3c5dabcea6696ce31848967a8f3f0 Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Sat, 6 May 2017 15:04:42 +0200 Subject: [PATCH] #777 Set initial capacity for new collection / map element in collection / map mappings --- .../model/ContainerMappingMethod.java | 12 + .../ap/internal/model/IterableCreation.java | 87 ++++++ .../ap/internal/model/MapMappingMethod.java | 12 + .../model/common/ImplementationType.java | 87 ++++++ .../ap/internal/model/common/Type.java | 8 +- .../ap/internal/model/common/TypeFactory.java | 46 +-- .../ap/internal/model/IterableCreation.ftl | 50 ++++ .../internal/model/IterableMappingMethod.ftl | 19 +- .../ap/internal/model/MapMappingMethod.ftl | 19 +- .../ap/internal/model/StreamMappingMethod.ftl | 17 +- .../DefaultCollectionImplementationTest.java | 6 + .../ap/test/array/ScienceMapperImpl.java | 6 +- .../DomainDtoWithNcvsAlwaysMapperImpl.java | 4 +- .../DomainDtoWithNvmsDefaultMapperImpl.java | 6 +- .../_913/DomainDtoWithNvmsNullMapperImpl.java | 6 +- .../DomainDtoWithPresenceCheckMapperImpl.java | 4 +- .../SourceTargetMapperImpl.java | 272 ++++++++++++++++++ .../nestedbeans/UserDtoMapperClassicImpl.java | 6 +- .../nestedbeans/UserDtoMapperSmartImpl.java | 8 +- .../UserDtoUpdateMapperSmartImpl.java | 6 +- .../updatemethods/CompanyMapper1Impl.java | 6 +- 21 files changed, 595 insertions(+), 92 deletions(-) create mode 100644 processor/src/main/java/org/mapstruct/ap/internal/model/IterableCreation.java create mode 100644 processor/src/main/java/org/mapstruct/ap/internal/model/common/ImplementationType.java create mode 100644 processor/src/main/resources/org/mapstruct/ap/internal/model/IterableCreation.ftl create mode 100644 processor/src/test/resources/fixtures/org/mapstruct/ap/test/collection/defaultimplementation/SourceTargetMapperImpl.java diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/ContainerMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/internal/model/ContainerMappingMethod.java index 8628ebe5b..984753509 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/ContainerMappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/ContainerMappingMethod.java @@ -42,6 +42,7 @@ public abstract class ContainerMappingMethod extends NormalTypeMappingMethod { private final SelectionParameters selectionParameters; private final String index1Name; private final String index2Name; + private IterableCreation iterableCreation; ContainerMappingMethod(Method method, Collection existingVariables, Assignment parameterAssignment, MethodReference factoryMethod, boolean mapNullToDefault, String loopVariableName, @@ -67,6 +68,13 @@ public abstract class ContainerMappingMethod extends NormalTypeMappingMethod { throw new IllegalStateException( "Method " + this + " has no source parameter." ); } + public IterableCreation getIterableCreation() { + if ( iterableCreation == null ) { + iterableCreation = IterableCreation.create( this, getSourceParameter() ); + } + return iterableCreation; + } + public Assignment getElementAssignment() { return elementAssignment; } @@ -77,6 +85,10 @@ public abstract class ContainerMappingMethod extends NormalTypeMappingMethod { if ( elementAssignment != null ) { types.addAll( elementAssignment.getImportTypes() ); } + + if ( iterableCreation != null ) { + types.addAll( iterableCreation.getImportTypes() ); + } return types; } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/IterableCreation.java b/processor/src/main/java/org/mapstruct/ap/internal/model/IterableCreation.java new file mode 100644 index 000000000..e54cd98b8 --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/IterableCreation.java @@ -0,0 +1,87 @@ +/** + * 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.internal.model; + +import java.util.HashSet; +import java.util.Set; + +import org.mapstruct.ap.internal.model.common.ModelElement; +import org.mapstruct.ap.internal.model.common.Parameter; +import org.mapstruct.ap.internal.model.common.Type; + +/** + * Model element that can be used to create a type of {@link Iterable} or {@link java.util.Map}. If an implementation + * type is used and the target type has a constructor with {@link int} as parameter and the source parameter is of + * {@link java.util.Collection}, {@link java.util.Map} or {@code Array} type then MapStruct will use that constructor + * with the {@code size} / {@code length} from the source parameter. + * + * @author Filip Hrisafov + */ +public class IterableCreation extends ModelElement { + + private final Type resultType; + private final Parameter sourceParameter; + private final MethodReference factoryMethod; + private final boolean canUseSize; + private final boolean loadFactorAdjustment; + + private IterableCreation(Type resultType, Parameter sourceParameter, MethodReference factoryMethod) { + this.resultType = resultType; + this.sourceParameter = sourceParameter; + this.factoryMethod = factoryMethod; + this.canUseSize = ( sourceParameter.getType().isCollectionOrMapType() || + sourceParameter.getType().isArrayType() ) + && resultType.getImplementation() != null && resultType.getImplementation().hasInitialCapacityConstructor(); + this.loadFactorAdjustment = this.canUseSize && resultType.getImplementation().isLoadFactorAdjustment(); + + } + + public static IterableCreation create(NormalTypeMappingMethod mappingMethod, Parameter sourceParameter) { + return new IterableCreation( mappingMethod.getResultType(), sourceParameter, mappingMethod.getFactoryMethod() ); + } + + public Type getResultType() { + return resultType; + } + + public Parameter getSourceParameter() { + return sourceParameter; + } + + public MethodReference getFactoryMethod() { + return this.factoryMethod; + } + + public boolean isCanUseSize() { + return canUseSize; + } + + public boolean isLoadFactorAdjustment() { + return loadFactorAdjustment; + } + + @Override + public Set getImportTypes() { + Set types = new HashSet(); + if ( factoryMethod == null && resultType.getImplementationType() != null ) { + types.addAll( resultType.getImplementationType().getImportTypes() ); + } + return types; + } +} diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/MapMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/internal/model/MapMappingMethod.java index b94a18b37..6b781a3cc 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/MapMappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/MapMappingMethod.java @@ -47,6 +47,7 @@ public class MapMappingMethod extends NormalTypeMappingMethod { private final Assignment keyAssignment; private final Assignment valueAssignment; + private IterableCreation iterableCreation; public static class Builder extends AbstractMappingMethodBuilder { @@ -268,6 +269,10 @@ public class MapMappingMethod extends NormalTypeMappingMethod { types.addAll( valueAssignment.getImportTypes() ); } + if ( iterableCreation != null ) { + types.addAll( iterableCreation.getImportTypes() ); + } + return types; } @@ -291,4 +296,11 @@ public class MapMappingMethod extends NormalTypeMappingMethod { getParameterNames() ); } + + public IterableCreation getIterableCreation() { + if ( iterableCreation == null ) { + iterableCreation = IterableCreation.create( this, getSourceParameter() ); + } + return iterableCreation; + } } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/common/ImplementationType.java b/processor/src/main/java/org/mapstruct/ap/internal/model/common/ImplementationType.java new file mode 100644 index 000000000..8ddb2356b --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/common/ImplementationType.java @@ -0,0 +1,87 @@ +/** + * 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.internal.model.common; + +/** + * This is a wrapper class for the Implementation types that are used within MapStruct. It contains all the + * information needed for an Iterable creation + * + * @author Filip Hrisafov + */ +public class ImplementationType { + + private final Type type; + private final boolean initialCapacityConstructor; + private final boolean loadFactorAdjustment; + + private ImplementationType(Type type, boolean initialCapacityConstructor, boolean loadFactorAdjustment) { + this.type = type; + this.initialCapacityConstructor = initialCapacityConstructor; + this.loadFactorAdjustment = loadFactorAdjustment; + } + + public static ImplementationType withDefaultConstructor(Type type) { + return new ImplementationType( type, false, false ); + } + + public static ImplementationType withInitialCapacity(Type type) { + return new ImplementationType( type, true, false ); + } + + public static ImplementationType withLoadFactorAdjustment(Type type) { + return new ImplementationType( type, true, true ); + } + + /** + * Creates new {@link ImplementationType} that has the same {@link #initialCapacityConstructor} and + * {@link #loadFactorAdjustment}, but a different underlying {@link Type} + * + * @param type to be replaced + * + * @return a new implementation type with the given {@code type} + */ + public ImplementationType createNew(Type type) { + return new ImplementationType( type, initialCapacityConstructor, loadFactorAdjustment ); + } + + /** + * @return the underlying {@link Type} + */ + public Type getType() { + return type; + } + + /** + * @return {@code true} if the underlying type has a constructor for {@link int} {@code initialCapacity}, {@code + * false} otherwise + */ + public boolean hasInitialCapacityConstructor() { + return initialCapacityConstructor; + } + + /** + * If this method returns {@code true} then {@link #hasInitialCapacityConstructor()} also returns {@code true} + * + * @return {@code true} if the underlying type needs adjustment for the initial capacity constructor, {@code + * false} otherwise + */ + public boolean isLoadFactorAdjustment() { + return loadFactorAdjustment; + } +} 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 3be805723..cb089e6e7 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 @@ -70,7 +70,7 @@ public class Type extends ModelElement implements Comparable { private final TypeElement typeElement; private final List typeParameters; - private final Type implementationType; + private final ImplementationType implementationType; private final Type componentType; private final String packageName; @@ -103,7 +103,7 @@ public class Type extends ModelElement implements Comparable { //CHECKSTYLE:OFF public Type(Types typeUtils, Elements elementUtils, TypeFactory typeFactory, TypeMirror typeMirror, TypeElement typeElement, - List typeParameters, Type implementationType, Type componentType, + List typeParameters, ImplementationType implementationType, Type componentType, String packageName, String name, String qualifiedName, boolean isInterface, boolean isEnumType, boolean isIterableType, boolean isCollectionType, boolean isMapType, boolean isStreamType, boolean isImported) { @@ -209,6 +209,10 @@ public class Type extends ModelElement implements Comparable { * type, {@code null} otherwise. */ public Type getImplementationType() { + return implementationType != null ? implementationType.getType() : null; + } + + public ImplementationType getImplementation() { return implementationType; } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/common/TypeFactory.java b/processor/src/main/java/org/mapstruct/ap/internal/model/common/TypeFactory.java index 7001b6bfa..b8a40333d 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/common/TypeFactory.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/common/TypeFactory.java @@ -61,6 +61,10 @@ import org.mapstruct.ap.internal.util.TypeHierarchyErroneousException; import org.mapstruct.ap.internal.util.accessor.Accessor; import org.mapstruct.ap.spi.AstModifyingAnnotationProcessor; +import static org.mapstruct.ap.internal.model.common.ImplementationType.withDefaultConstructor; +import static org.mapstruct.ap.internal.model.common.ImplementationType.withInitialCapacity; +import static org.mapstruct.ap.internal.model.common.ImplementationType.withLoadFactorAdjustment; + /** * Factory creating {@link Type} instances. * @@ -77,7 +81,7 @@ public class TypeFactory { private final TypeMirror mapType; private final TypeMirror streamType; - private final Map implementationTypes = new HashMap(); + private final Map implementationTypes = new HashMap(); private final Map importedQualifiedTypesBySimpleName = new HashMap(); public TypeFactory(Elements elementUtils, Types typeUtils, RoundContext roundContext) { @@ -92,19 +96,25 @@ public class TypeFactory { TypeElement streamTypeElement = elementUtils.getTypeElement( JavaStreamConstants.STREAM_FQN ); streamType = streamTypeElement == null ? null : typeUtils.erasure( streamTypeElement.asType() ); - implementationTypes.put( Iterable.class.getName(), getType( ArrayList.class ) ); - implementationTypes.put( Collection.class.getName(), getType( ArrayList.class ) ); - implementationTypes.put( List.class.getName(), getType( ArrayList.class ) ); + implementationTypes.put( Iterable.class.getName(), withInitialCapacity( getType( ArrayList.class ) ) ); + implementationTypes.put( Collection.class.getName(), withInitialCapacity( getType( ArrayList.class ) ) ); + implementationTypes.put( List.class.getName(), withInitialCapacity( getType( ArrayList.class ) ) ); - implementationTypes.put( Set.class.getName(), getType( HashSet.class ) ); - implementationTypes.put( SortedSet.class.getName(), getType( TreeSet.class ) ); - implementationTypes.put( NavigableSet.class.getName(), getType( TreeSet.class ) ); + implementationTypes.put( Set.class.getName(), withLoadFactorAdjustment( getType( HashSet.class ) ) ); + implementationTypes.put( SortedSet.class.getName(), withDefaultConstructor( getType( TreeSet.class ) ) ); + implementationTypes.put( NavigableSet.class.getName(), withDefaultConstructor( getType( TreeSet.class ) ) ); - implementationTypes.put( Map.class.getName(), getType( HashMap.class ) ); - implementationTypes.put( SortedMap.class.getName(), getType( TreeMap.class ) ); - implementationTypes.put( NavigableMap.class.getName(), getType( TreeMap.class ) ); - implementationTypes.put( ConcurrentMap.class.getName(), getType( ConcurrentHashMap.class ) ); - implementationTypes.put( ConcurrentNavigableMap.class.getName(), getType( ConcurrentSkipListMap.class ) ); + implementationTypes.put( Map.class.getName(), withLoadFactorAdjustment( getType( HashMap.class ) ) ); + implementationTypes.put( SortedMap.class.getName(), withDefaultConstructor( getType( TreeMap.class ) ) ); + implementationTypes.put( NavigableMap.class.getName(), withDefaultConstructor( getType( TreeMap.class ) ) ); + implementationTypes.put( + ConcurrentMap.class.getName(), + withLoadFactorAdjustment( getType( ConcurrentHashMap.class ) ) + ); + implementationTypes.put( + ConcurrentNavigableMap.class.getName(), + withDefaultConstructor( getType( ConcurrentSkipListMap.class ) ) + ); } public Type getType(Class type) { @@ -151,7 +161,7 @@ public class TypeFactory { throw new TypeHierarchyErroneousException( mirror ); } - Type implementationType = getImplementationType( mirror ); + ImplementationType implementationType = getImplementationType( mirror ); boolean isIterableType = typeUtils.isSubtype( mirror, iterableType ); boolean isCollectionType = typeUtils.isSubtype( mirror, collectionType ); @@ -397,20 +407,21 @@ public class TypeFactory { typeUtils.getPrimitiveType( TypeKind.VOID ); } - private Type getImplementationType(TypeMirror mirror) { + private ImplementationType getImplementationType(TypeMirror mirror) { if ( mirror.getKind() != TypeKind.DECLARED ) { return null; } DeclaredType declaredType = (DeclaredType) mirror; - Type implementationType = implementationTypes.get( + ImplementationType implementation = implementationTypes.get( ( (TypeElement) declaredType.asElement() ).getQualifiedName() .toString() ); - if ( implementationType != null ) { - return new Type( + if ( implementation != null ) { + Type implementationType = implementation.getType(); + Type replacement = new Type( typeUtils, elementUtils, this, @@ -433,6 +444,7 @@ public class TypeFactory { implementationType.isStreamType(), isImported( implementationType.getName(), implementationType.getFullyQualifiedName() ) ); + return implementation.createNew( replacement ); } return null; diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/IterableCreation.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/IterableCreation.ftl new file mode 100644 index 000000000..5c3f95c49 --- /dev/null +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/IterableCreation.ftl @@ -0,0 +1,50 @@ +<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.IterableCreation" --> +<#-- + + 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. + +--> +<@compress single_line=true> + <#if factoryMethod??> + <@includeModel object=factoryMethod targetType=resultType/> + <#else> + new + <#if resultType.implementationType??> + <@includeModel object=resultType.implementationType/><#if ext.useSizeIfPossible?? && ext.useSizeIfPossible && canUseSize>( <@sizeForCreation /> )<#else>() + <#else> + <@includeModel object=resultType/>() + + +<#macro sizeForCreation> + <@compress single_line=true> + <#if loadFactorAdjustment> + Math.max( (int) ( <@iterableSize/> / .75f ) + 1, 16 ) + <#else> + <@iterableSize/> + + + +<#macro iterableSize> + <@compress single_line=true> + <#if sourceParameter.type.arrayType> + ${sourceParameter.name}.length + <#else> + ${sourceParameter.name}.size() + + + \ No newline at end of file diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/IterableMappingMethod.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/IterableMappingMethod.ftl index a06c5d9e5..3e404ede6 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/IterableMappingMethod.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/IterableMappingMethod.ftl @@ -47,7 +47,7 @@ ${resultName}.clear(); return<#if returnType.name != "void"> ${resultName}; <#else> - return <@iterableCreation/>; + return <@includeModel object=iterableCreation useSizeIfPossible=false/>; @@ -63,7 +63,7 @@ ${resultName}.clear(); <#else> <#-- Use the interface type on the left side, except it is java.lang.Iterable; use the implementation type - if present - on the right side --> - <@iterableLocalVarDef/> ${resultName} = <@iterableCreation/>; + <@iterableLocalVarDef/> ${resultName} = <@includeModel object=iterableCreation useSizeIfPossible=true/>; <#list beforeMappingReferencesWithMappingTarget as callback> @@ -124,17 +124,4 @@ <@includeModel object=resultType/> - -<#macro iterableCreation> - <@compress single_line=true> - <#if factoryMethod??> - <@includeModel object=factoryMethod targetType=resultType/> - <#else> - new - <#if resultType.implementationType??> - <@includeModel object=resultType.implementationType/> - <#else> - <@includeModel object=resultType/>() - - - + \ No newline at end of file diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/MapMappingMethod.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/MapMappingMethod.ftl index 9acca2636..ed6d90300 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/MapMappingMethod.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/MapMappingMethod.ftl @@ -35,7 +35,7 @@ ${resultName}.clear(); return<#if returnType.name != "void"> ${resultName}; <#else> - return <@returnObjectCreation/>; + return <@includeModel object=iterableCreation useSizeIfPossible=false/>; } @@ -43,7 +43,7 @@ <#if existingInstanceMapping> ${resultName}.clear(); <#else> - <@includeModel object=resultType /> ${resultName} = <@returnObjectCreation/>; + <@includeModel object=resultType /> ${resultName} = <@includeModel object=iterableCreation useSizeIfPossible=true/>; <#list beforeMappingReferencesWithMappingTarget as callback> @@ -82,17 +82,4 @@ <#if exceptionType_has_next>, <#t> - -<#macro returnObjectCreation> - <@compress single_line=true> - <#if factoryMethod??> - <@includeModel object=factoryMethod targetType=resultType/> - <#else> - new - <#if resultType.implementationType??> - <@includeModel object=resultType.implementationType /> - <#else> - <@includeModel object=resultType />() - - - + \ No newline at end of file diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/StreamMappingMethod.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/StreamMappingMethod.ftl index eadfa67b5..f8877a02e 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/StreamMappingMethod.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/StreamMappingMethod.ftl @@ -48,7 +48,7 @@ ${resultName}.clear(); return<#if returnType.name != "void"> ${resultName}; <#else> - return <@iterableCreation/>; + return <@includeModel object=iterableCreation useSizeIfPossible=false/>; <#else> <#if existingInstanceMapping> @@ -76,7 +76,7 @@ <#elseif needVarDefine> <#assign needVarDefine = false /> <#-- Use the interface type on the left side, except it is java.lang.Iterable; use the implementation type - if present - on the right side --> - <@iterableLocalVarDef/> ${resultName} = <@iterableCreation/>; + <@iterableLocalVarDef/> ${resultName} = <@includeModel object=iterableCreation useSizeIfPossible=true/>; <#else> <#-- Streams are immutable so we can't update them --> @@ -177,19 +177,6 @@ -<#macro iterableCreation> - <@compress single_line=true> - <#if factoryMethod??> - <@includeModel object=factoryMethod targetType=resultType/> - <#else> - new - <#if resultType.implementationType??> - <@includeModel object=resultType.implementationType/> - <#else> - <@includeModel object=resultType/>() - - - <#macro iterableCollectionSupplier> <@compress single_line=true> <#if resultType.implementationType??> diff --git a/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/DefaultCollectionImplementationTest.java b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/DefaultCollectionImplementationTest.java index 3dba235cd..ce6a0a245 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/DefaultCollectionImplementationTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/DefaultCollectionImplementationTest.java @@ -36,11 +36,13 @@ import java.util.SortedSet; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentNavigableMap; +import org.junit.Rule; 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 org.mapstruct.ap.testutil.runner.GeneratedSource; @WithClasses({ Source.class, @@ -52,6 +54,10 @@ import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner; @RunWith(AnnotationProcessorTestRunner.class) public class DefaultCollectionImplementationTest { + @Rule + public final GeneratedSource generatedSource = new GeneratedSource() + .addComparisonToFixtureFor( SourceTargetMapper.class ); + @Test @IssueKey("6") public void shouldUseDefaultImplementationForConcurrentMap() { diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/array/ScienceMapperImpl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/array/ScienceMapperImpl.java index 71db5a9da..b2769fa89 100644 --- a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/array/ScienceMapperImpl.java +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/array/ScienceMapperImpl.java @@ -28,8 +28,8 @@ import org.mapstruct.ap.test.array.source.Scientist; @Generated( value = "org.mapstruct.ap.MappingProcessor", - date = "2016-12-28T17:52:06+0100", - comments = "version: , compiler: javac, environment: Java 1.8.0_112 (Oracle Corporation)" + date = "2017-05-03T23:47:43+0200", + comments = "version: , compiler: javac, environment: Java 1.8.0_131 (Oracle Corporation)" ) public class ScienceMapperImpl implements ScienceMapper { @@ -94,7 +94,7 @@ public class ScienceMapperImpl implements ScienceMapper { return null; } - List list = new ArrayList(); + List list = new ArrayList( scientists.length ); for ( Scientist scientist : scientists ) { list.add( scientistToDto( scientist ) ); } diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/bugs/_913/DomainDtoWithNcvsAlwaysMapperImpl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/bugs/_913/DomainDtoWithNcvsAlwaysMapperImpl.java index bb1a5356d..22427cba8 100644 --- a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/bugs/_913/DomainDtoWithNcvsAlwaysMapperImpl.java +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/bugs/_913/DomainDtoWithNcvsAlwaysMapperImpl.java @@ -26,7 +26,7 @@ import javax.annotation.Generated; @Generated( value = "org.mapstruct.ap.MappingProcessor", - date = "2017-04-22T09:19:18+0200", + date = "2017-05-06T00:06:20+0200", comments = "version: , compiler: javac, environment: Java 1.8.0_131 (Oracle Corporation)" ) public class DomainDtoWithNcvsAlwaysMapperImpl implements DomainDtoWithNcvsAlwaysMapper { @@ -229,7 +229,7 @@ public class DomainDtoWithNcvsAlwaysMapperImpl implements DomainDtoWithNcvsAlway return null; } - Set set = new HashSet(); + Set set = new HashSet( Math.max( (int) ( list.size() / .75f ) + 1, 16 ) ); for ( String string : list ) { set.add( Long.parseLong( string ) ); } diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/bugs/_913/DomainDtoWithNvmsDefaultMapperImpl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/bugs/_913/DomainDtoWithNvmsDefaultMapperImpl.java index cad3066b5..241edfc2f 100644 --- a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/bugs/_913/DomainDtoWithNvmsDefaultMapperImpl.java +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/bugs/_913/DomainDtoWithNvmsDefaultMapperImpl.java @@ -26,8 +26,8 @@ import javax.annotation.Generated; @Generated( value = "org.mapstruct.ap.MappingProcessor", - date = "2017-04-09T23:02:48+0200", - comments = "version: , compiler: javac, environment: Java 1.8.0_121 (Oracle Corporation)" + date = "2017-05-06T00:06:21+0200", + comments = "version: , compiler: javac, environment: Java 1.8.0_131 (Oracle Corporation)" ) public class DomainDtoWithNvmsDefaultMapperImpl implements DomainDtoWithNvmsDefaultMapper { @@ -254,7 +254,7 @@ public class DomainDtoWithNvmsDefaultMapperImpl implements DomainDtoWithNvmsDefa return new HashSet(); } - Set set = new HashSet(); + Set set = new HashSet( Math.max( (int) ( list.size() / .75f ) + 1, 16 ) ); for ( String string : list ) { set.add( Long.parseLong( string ) ); } diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/bugs/_913/DomainDtoWithNvmsNullMapperImpl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/bugs/_913/DomainDtoWithNvmsNullMapperImpl.java index e4683414b..21cadd539 100644 --- a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/bugs/_913/DomainDtoWithNvmsNullMapperImpl.java +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/bugs/_913/DomainDtoWithNvmsNullMapperImpl.java @@ -26,8 +26,8 @@ import javax.annotation.Generated; @Generated( value = "org.mapstruct.ap.MappingProcessor", - date = "2017-04-09T23:02:47+0200", - comments = "version: , compiler: javac, environment: Java 1.8.0_121 (Oracle Corporation)" + date = "2017-05-06T00:06:20+0200", + comments = "version: , compiler: javac, environment: Java 1.8.0_131 (Oracle Corporation)" ) public class DomainDtoWithNvmsNullMapperImpl implements DomainDtoWithNvmsNullMapper { @@ -257,7 +257,7 @@ public class DomainDtoWithNvmsNullMapperImpl implements DomainDtoWithNvmsNullMap return null; } - Set set = new HashSet(); + Set set = new HashSet( Math.max( (int) ( list.size() / .75f ) + 1, 16 ) ); for ( String string : list ) { set.add( Long.parseLong( string ) ); } diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/bugs/_913/DomainDtoWithPresenceCheckMapperImpl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/bugs/_913/DomainDtoWithPresenceCheckMapperImpl.java index 1b9bb3bbc..37dc9ceab 100644 --- a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/bugs/_913/DomainDtoWithPresenceCheckMapperImpl.java +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/bugs/_913/DomainDtoWithPresenceCheckMapperImpl.java @@ -26,7 +26,7 @@ import javax.annotation.Generated; @Generated( value = "org.mapstruct.ap.MappingProcessor", - date = "2017-04-22T09:19:17+0200", + date = "2017-05-06T00:06:21+0200", comments = "version: , compiler: javac, environment: Java 1.8.0_131 (Oracle Corporation)" ) public class DomainDtoWithPresenceCheckMapperImpl implements DomainDtoWithPresenceCheckMapper { @@ -219,7 +219,7 @@ public class DomainDtoWithPresenceCheckMapperImpl implements DomainDtoWithPresen return null; } - Set set = new HashSet(); + Set set = new HashSet( Math.max( (int) ( list.size() / .75f ) + 1, 16 ) ); for ( String string : list ) { set.add( Long.parseLong( string ) ); } diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/collection/defaultimplementation/SourceTargetMapperImpl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/collection/defaultimplementation/SourceTargetMapperImpl.java new file mode 100644 index 000000000..7b39e52bc --- /dev/null +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/collection/defaultimplementation/SourceTargetMapperImpl.java @@ -0,0 +1,272 @@ +/** + * 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.collection.defaultimplementation; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.NavigableMap; +import java.util.NavigableSet; +import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentNavigableMap; +import java.util.concurrent.ConcurrentSkipListMap; +import javax.annotation.Generated; + +@Generated( + value = "org.mapstruct.ap.MappingProcessor", + date = "2017-05-06T00:20:29+0200", + comments = "version: , compiler: javac, environment: Java 1.8.0_131 (Oracle Corporation)" +) +public class SourceTargetMapperImpl implements SourceTargetMapper { + + @Override + public Target sourceToTarget(Source source) { + if ( source == null ) { + return null; + } + + Target target = new Target(); + + if ( target.getFooListNoSetter() != null ) { + List list = sourceFoosToTargetFoos( source.getFooList() ); + if ( list != null ) { + target.getFooListNoSetter().addAll( list ); + } + } + + return target; + } + + @Override + public TargetFoo sourceFooToTargetFoo(SourceFoo sourceFoo) { + if ( sourceFoo == null ) { + return null; + } + + TargetFoo targetFoo = new TargetFoo(); + + targetFoo.setName( sourceFoo.getName() ); + + return targetFoo; + } + + @Override + public List sourceFoosToTargetFoos(List foos) { + if ( foos == null ) { + return null; + } + + List list = new ArrayList( foos.size() ); + for ( SourceFoo sourceFoo : foos ) { + list.add( sourceFooToTargetFoo( sourceFoo ) ); + } + + return list; + } + + @Override + public Set sourceFoosToTargetFoos(Set foos) { + if ( foos == null ) { + return null; + } + + Set set = new HashSet( Math.max( (int) ( foos.size() / .75f ) + 1, 16 ) ); + for ( SourceFoo sourceFoo : foos ) { + set.add( sourceFooToTargetFoo( sourceFoo ) ); + } + + return set; + } + + @Override + public Collection sourceFoosToTargetFoos(Collection foos) { + if ( foos == null ) { + return null; + } + + Collection collection = new ArrayList( foos.size() ); + for ( SourceFoo sourceFoo : foos ) { + collection.add( sourceFooToTargetFoo( sourceFoo ) ); + } + + return collection; + } + + @Override + public Iterable sourceFoosToTargetFoos(Iterable foos) { + if ( foos == null ) { + return null; + } + + ArrayList iterable = new ArrayList(); + for ( SourceFoo sourceFoo : foos ) { + iterable.add( sourceFooToTargetFoo( sourceFoo ) ); + } + + return iterable; + } + + @Override + public void sourceFoosToTargetFoosUsingTargetParameter(List targetFoos, Iterable sourceFoos) { + if ( sourceFoos == null ) { + return; + } + + targetFoos.clear(); + for ( SourceFoo sourceFoo : sourceFoos ) { + targetFoos.add( sourceFooToTargetFoo( sourceFoo ) ); + } + } + + @Override + public Iterable sourceFoosToTargetFoosUsingTargetParameterAndReturn(Iterable sourceFoos, List targetFoos) { + if ( sourceFoos == null ) { + return null; + } + + targetFoos.clear(); + for ( SourceFoo sourceFoo : sourceFoos ) { + targetFoos.add( sourceFooToTargetFoo( sourceFoo ) ); + } + + return targetFoos; + } + + @Override + public SortedSet sourceFoosToTargetFooSortedSet(Collection foos) { + if ( foos == null ) { + return null; + } + + SortedSet sortedSet = new TreeSet(); + for ( SourceFoo sourceFoo : foos ) { + sortedSet.add( sourceFooToTargetFoo( sourceFoo ) ); + } + + return sortedSet; + } + + @Override + public NavigableSet sourceFoosToTargetFooNavigableSet(Collection foos) { + if ( foos == null ) { + return null; + } + + NavigableSet navigableSet = new TreeSet(); + for ( SourceFoo sourceFoo : foos ) { + navigableSet.add( sourceFooToTargetFoo( sourceFoo ) ); + } + + return navigableSet; + } + + @Override + public Map sourceFooMapToTargetFooMap(Map foos) { + if ( foos == null ) { + return null; + } + + Map map = new HashMap( Math.max( (int) ( foos.size() / .75f ) + 1, 16 ) ); + + for ( java.util.Map.Entry entry : foos.entrySet() ) { + String key = String.valueOf( entry.getKey() ); + TargetFoo value = sourceFooToTargetFoo( entry.getValue() ); + map.put( key, value ); + } + + return map; + } + + @Override + public SortedMap sourceFooMapToTargetFooSortedMap(Map foos) { + if ( foos == null ) { + return null; + } + + SortedMap sortedMap = new TreeMap(); + + for ( java.util.Map.Entry entry : foos.entrySet() ) { + String key = String.valueOf( entry.getKey() ); + TargetFoo value = sourceFooToTargetFoo( entry.getValue() ); + sortedMap.put( key, value ); + } + + return sortedMap; + } + + @Override + public NavigableMap sourceFooMapToTargetFooNavigableMap(Map foos) { + if ( foos == null ) { + return null; + } + + NavigableMap navigableMap = new TreeMap(); + + for ( java.util.Map.Entry entry : foos.entrySet() ) { + String key = String.valueOf( entry.getKey() ); + TargetFoo value = sourceFooToTargetFoo( entry.getValue() ); + navigableMap.put( key, value ); + } + + return navigableMap; + } + + @Override + public ConcurrentMap sourceFooMapToTargetFooConcurrentMap(Map foos) { + if ( foos == null ) { + return null; + } + + ConcurrentMap concurrentMap = new ConcurrentHashMap( Math.max( (int) ( foos.size() / .75f ) + 1, 16 ) ); + + for ( java.util.Map.Entry entry : foos.entrySet() ) { + String key = String.valueOf( entry.getKey() ); + TargetFoo value = sourceFooToTargetFoo( entry.getValue() ); + concurrentMap.put( key, value ); + } + + return concurrentMap; + } + + @Override + public ConcurrentNavigableMap sourceFooMapToTargetFooConcurrentNavigableMap(Map foos) { + if ( foos == null ) { + return null; + } + + ConcurrentNavigableMap concurrentNavigableMap = new ConcurrentSkipListMap(); + + for ( java.util.Map.Entry entry : foos.entrySet() ) { + String key = String.valueOf( entry.getKey() ); + TargetFoo value = sourceFooToTargetFoo( entry.getValue() ); + concurrentNavigableMap.put( key, value ); + } + + return concurrentNavigableMap; + } +} diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/nestedbeans/UserDtoMapperClassicImpl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/nestedbeans/UserDtoMapperClassicImpl.java index b2616c892..00517eb4a 100644 --- a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/nestedbeans/UserDtoMapperClassicImpl.java +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/nestedbeans/UserDtoMapperClassicImpl.java @@ -24,8 +24,8 @@ import javax.annotation.Generated; @Generated( value = "org.mapstruct.ap.MappingProcessor", - date = "2017-04-09T23:25:54+0200", - comments = "version: , compiler: javac, environment: Java 1.8.0_121 (Oracle Corporation)" + date = "2017-05-04T00:00:46+0200", + comments = "version: , compiler: javac, environment: Java 1.8.0_131 (Oracle Corporation)" ) public class UserDtoMapperClassicImpl implements UserDtoMapperClassic { @@ -95,7 +95,7 @@ public class UserDtoMapperClassicImpl implements UserDtoMapperClassic { return null; } - List list = new ArrayList(); + List list = new ArrayList( wheels.size() ); for ( Wheel wheel : wheels ) { list.add( mapWheel( wheel ) ); } diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/nestedbeans/UserDtoMapperSmartImpl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/nestedbeans/UserDtoMapperSmartImpl.java index 5f16703a4..12bcc738e 100644 --- a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/nestedbeans/UserDtoMapperSmartImpl.java +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/nestedbeans/UserDtoMapperSmartImpl.java @@ -24,8 +24,8 @@ import javax.annotation.Generated; @Generated( value = "org.mapstruct.ap.MappingProcessor", - date = "2017-04-09T23:25:54+0200", - comments = "version: , compiler: javac, environment: Java 1.8.0_121 (Oracle Corporation)" + date = "2017-05-04T00:00:47+0200", + comments = "version: , compiler: javac, environment: Java 1.8.0_131 (Oracle Corporation)" ) public class UserDtoMapperSmartImpl implements UserDtoMapperSmart { @@ -78,7 +78,7 @@ public class UserDtoMapperSmartImpl implements UserDtoMapperSmart { return null; } - List list1 = new ArrayList(); + List list1 = new ArrayList( list.size() ); for ( Wheel wheel : list ) { list1.add( wheelToWheelDto( wheel ) ); } @@ -165,7 +165,7 @@ public class UserDtoMapperSmartImpl implements UserDtoMapperSmart { return null; } - List list1 = new ArrayList(); + List list1 = new ArrayList( list.size() ); for ( Wheel wheel : list ) { list1.add( wheelToWheelDto1( wheel ) ); } diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/nestedbeans/UserDtoUpdateMapperSmartImpl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/nestedbeans/UserDtoUpdateMapperSmartImpl.java index c24ec1707..28594ec1a 100644 --- a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/nestedbeans/UserDtoUpdateMapperSmartImpl.java +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/nestedbeans/UserDtoUpdateMapperSmartImpl.java @@ -24,8 +24,8 @@ import javax.annotation.Generated; @Generated( value = "org.mapstruct.ap.MappingProcessor", - date = "2017-03-01T22:15:22+0100", - comments = "version: , compiler: javac, environment: Java 1.8.0_112 (Oracle Corporation)" + date = "2017-05-04T00:00:45+0200", + comments = "version: , compiler: javac, environment: Java 1.8.0_131 (Oracle Corporation)" ) public class UserDtoUpdateMapperSmartImpl implements UserDtoUpdateMapperSmart { @@ -85,7 +85,7 @@ public class UserDtoUpdateMapperSmartImpl implements UserDtoUpdateMapperSmart { return null; } - List list1 = new ArrayList(); + List list1 = new ArrayList( list.size() ); for ( Wheel wheel : list ) { list1.add( wheelToWheelDto( wheel ) ); } diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/updatemethods/CompanyMapper1Impl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/updatemethods/CompanyMapper1Impl.java index d1f212f5d..352b0a10e 100644 --- a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/updatemethods/CompanyMapper1Impl.java +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/updatemethods/CompanyMapper1Impl.java @@ -24,8 +24,8 @@ import javax.annotation.Generated; @Generated( value = "org.mapstruct.ap.MappingProcessor", - date = "2017-03-13T22:32:15+0100", - comments = "version: , compiler: javac, environment: Java 1.8.0_121 (Oracle Corporation)" + date = "2017-05-06T00:11:06+0200", + comments = "version: , compiler: javac, environment: Java 1.8.0_131 (Oracle Corporation)" ) public class CompanyMapper1Impl implements CompanyMapper1 { @@ -96,7 +96,7 @@ public class CompanyMapper1Impl implements CompanyMapper1 { return null; } - Map map1 = new HashMap(); + Map map1 = new HashMap( Math.max( (int) ( map.size() / .75f ) + 1, 16 ) ); for ( java.util.Map.Entry entry : map.entrySet() ) { SecretaryEntity key = secretaryDtoToSecretaryEntity( entry.getKey() );