From 95745019453d52402eb6438c297cdc3f816e2f55 Mon Sep 17 00:00:00 2001 From: hduelme Date: Sat, 9 May 2026 22:26:20 +0200 Subject: [PATCH 1/3] add support for generics in Arrays and fix initialization of multidimensional arrays --- .../ap/internal/model/common/Type.java | 179 ++++++++++++------ .../ap/internal/model/common/TypeFactory.java | 3 + .../internal/model/IterableMappingMethod.ftl | 24 ++- .../ap/internal/model/StreamMappingMethod.ftl | 7 +- .../ap/internal/model/common/Type.ftl | 3 +- .../ap/internal/model/macro/CommonMacros.ftl | 8 +- .../ap/test/array/ArrayMappingTest.java | 121 +++++++++++- .../ap/test/array/ScienceMapper.java | 31 ++- .../array/_target/GenericScientistDto.java | 50 +++++ .../test/array/source/GenericScientist.java | 46 +++++ .../ap/test/bugs/_895/Issue895Test.java | 44 ++++- .../ap/test/bugs/_895/MultiArrayMapper.java | 36 ++++ .../mapstruct/ap/test/java8stream/Source.java | 30 +++ .../test/java8stream/SourceTargetMapper.java | 5 +- .../test/java8stream/StreamMappingTest.java | 70 +++++++ .../mapstruct/ap/test/java8stream/Target.java | 30 +++ .../ap/test/array/ScienceMapperImpl.java | 155 ++++++++++++++- 17 files changed, 750 insertions(+), 92 deletions(-) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/array/_target/GenericScientistDto.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/array/source/GenericScientist.java 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 9133325e3e..37cefbed83 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 @@ -697,35 +697,66 @@ public Type replaceSuperBoundWith( Type compare, Type replacement ) { return this; } - DeclaredType declaredType = typeUtils.getDeclaredType( - typeElement, - mirrors - ); - return new Type( - typeUtils, - elementUtils, - typeFactory, - accessorNaming, - declaredType, - (TypeElement) declaredType.asElement(), - bounds, - implementationType, - componentType, - packageName, - name, - qualifiedName, - isInterface, - isEnumType, - isIterableType, - isCollectionType, - isMapType, - isStream, - toBeImportedTypes, - notToBeImportedTypes, - isToBeImported, - isLiteral, - loggingVerbose - ); + if ( this.componentType != null ) { + Type componentTypeWithoutBounds = this.componentType.replaceSuperBoundWith( compare, replacement ); + + return new Type( + typeUtils, + elementUtils, + typeFactory, + accessorNaming, + typeUtils.getArrayType( componentTypeWithoutBounds.getTypeMirror() ), + null, + bounds, + implementationType, + componentTypeWithoutBounds, + packageName, + name, + qualifiedName, + isInterface, + isEnumType, + isIterableType, + isCollectionType, + isMapType, + isStream, + toBeImportedTypes, + notToBeImportedTypes, + isToBeImported, + isLiteral, + loggingVerbose + ); + } + else { + DeclaredType declaredType = typeUtils.getDeclaredType( + typeElement, + mirrors + ); + return new Type( + typeUtils, + elementUtils, + typeFactory, + accessorNaming, + declaredType, + (TypeElement) declaredType.asElement(), + bounds, + implementationType, + componentType, + packageName, + name, + qualifiedName, + isInterface, + isEnumType, + isIterableType, + isCollectionType, + isMapType, + isStream, + toBeImportedTypes, + notToBeImportedTypes, + isToBeImported, + isLiteral, + loggingVerbose + ); + } } public Type withoutBounds() { @@ -740,39 +771,69 @@ public Type withoutBounds() { mirrors.add( typeParameter.getTypeBound().getTypeMirror() ); } - DeclaredType declaredType = typeUtils.getDeclaredType( - typeElement, - mirrors.toArray( new TypeMirror[] {} ) - ); - return new Type( - typeUtils, - elementUtils, - typeFactory, - accessorNaming, - declaredType, - (TypeElement) declaredType.asElement(), - bounds, - implementationType, - componentType, - packageName, - name, - qualifiedName, - isInterface, - isEnumType, - isIterableType, - isCollectionType, - isMapType, - isStream, - toBeImportedTypes, - notToBeImportedTypes, - isToBeImported, - isLiteral, - loggingVerbose - ); + if ( this.componentType != null ) { + Type componentTypeWithoutBounds = this.componentType.withoutBounds(); + + return new Type( + typeUtils, + elementUtils, + typeFactory, + accessorNaming, + typeUtils.getArrayType( componentTypeWithoutBounds.getTypeMirror() ), + null, + bounds, + implementationType, + componentTypeWithoutBounds, + packageName, + name, + qualifiedName, + isInterface, + isEnumType, + isIterableType, + isCollectionType, + isMapType, + isStream, + toBeImportedTypes, + notToBeImportedTypes, + isToBeImported, + isLiteral, + loggingVerbose + ); + } + else { + DeclaredType declaredType = typeUtils.getDeclaredType( + typeElement, + mirrors.toArray( new TypeMirror[] {} ) ); + return new Type( + typeUtils, + elementUtils, + typeFactory, + accessorNaming, + declaredType, + (TypeElement) declaredType.asElement(), + bounds, + implementationType, + null, + packageName, + name, + qualifiedName, + isInterface, + isEnumType, + isIterableType, + isCollectionType, + isMapType, + isStream, + toBeImportedTypes, + notToBeImportedTypes, + isToBeImported, + isLiteral, + loggingVerbose + ); + } } private Type replaceGeneric(Type oldGenericType, Type newType) { - if ( !typeParameters.contains( oldGenericType ) || newType == null ) { + if ( !typeParameters.contains( oldGenericType ) || newType == null || oldGenericType.equals( newType ) ) { return this; } newType = newType.getBoxedEquivalent(); 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 37c38ab590..8d79780d35 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 @@ -518,6 +518,9 @@ private List extractTypes(List typeMirrors) { } private List getTypeParameters(TypeMirror mirror, boolean isImplementationType) { + while ( mirror.getKind() == TypeKind.ARRAY ) { + mirror = getComponentType( mirror ); + } if ( mirror.getKind() != TypeKind.DECLARED ) { return java.util.Collections.emptyList(); } 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 7c3d3071ac..0e88d09972 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 @@ -6,6 +6,7 @@ --> <#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.IterableMappingMethod" --> +<#import "macro/CommonMacros.ftl" as lib> <#list annotations as annotation> <#nt><@includeModel object=annotation/> @@ -28,7 +29,7 @@ } return<#if returnType.name != "void"> ${resultName}; <#else> - return new <@includeModel object=resultElementType/>[0]; + return <@lib.constructArrayType targetType=resultType targetSize=0/>; <#else> <#if existingInstanceMapping> @@ -43,8 +44,7 @@ <#if resultType.arrayType> <#if !existingInstanceMapping> - <#assign elementTypeString><@includeModel object=resultElementType/> - ${elementTypeString}[] ${resultName} = new ${elementTypeString?keep_before('[]')}[<@iterableSize/>]${elementTypeString?replace('[^\\[\\]]+', '', 'r')}; + <@includeModel object=resultElementType/>[] ${resultName} = <@lib.constructArrayType targetType=resultType targetSize=iterableSize()/>; <#else> <#if existingInstanceMapping> @@ -64,7 +64,7 @@ int ${index1Name} = 0; for ( <@includeModel object=sourceElementType/> ${loopVariableName} : ${sourceParameter.name} ) { <#if existingInstanceMapping> - if ( ( ${index1Name} >= ${resultName}.length ) || ( ${index1Name} >= <@iterableSize/> ) ) { + if ( ( ${index1Name} >= ${resultName}.length ) || ( ${index1Name} >= ${iterableSize()} ) ) { break; } @@ -95,15 +95,13 @@ -<#macro iterableSize> - <@compress single_line=true> - <#if sourceParameter.type.arrayType> - ${sourceParameter.name}.length - <#else> - ${sourceParameter.name}.size() - - - +<#function iterableSize> + <#if sourceParameter.type.arrayType> + <#return sourceParameter.name + ".length"> + <#else> + <#return sourceParameter.name + ".size()"> + + <#macro iterableLocalVarDef> <@compress single_line=true> <#if resultType.fullyQualifiedName == "java.lang.Iterable"> 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 2269892b8a..3cd97ef9ee 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 @@ -6,6 +6,7 @@ --> <#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.StreamMappingMethod" --> +<#import "macro/CommonMacros.ftl" as lib> <#list annotations as annotation> <#nt><@includeModel object=annotation/> @@ -29,7 +30,7 @@ } return<#if returnType.name != "void"> ${resultName}; <#else> - return new <@includeModel object=resultElementType/>[0]; + return <@lib.constructArrayType targetType=resultType targetSize=0/>; <#elseif resultType.iterableType> <#if existingInstanceMapping> @@ -88,7 +89,7 @@ <#if resultType.arrayType> <#if existingInstanceMapping> int ${index1Name} = 0; - for ( <@includeModel object=resultElementType/> ${loopVariableName} : ${sourceParameter.name}.limit( ${resultName}.length )<@streamMapSupplier />.toArray( ${resultElementType}[]::new ) ) { + for ( <@includeModel object=resultElementType/> ${loopVariableName} : ${sourceParameter.name}.limit( ${resultName}.length )<@streamMapSupplier />.toArray( <@includeModel object=resultElementType raw=true/>[]::new ) ) { if ( ( ${index1Name} >= ${resultName}.length ) ) { break; } @@ -96,7 +97,7 @@ } <#else> <#if canReturnImmediatelly><#if returnType.name != "void">return <#else> <#if needVarDefine>${resultElementType}[] <#else>${resultName} = ${sourceParameter.name}<@streamMapSupplier /> - .toArray( <@includeModel object=resultElementType/>[]::new ); + .toArray( <@includeModel object=resultElementType raw=true/>[]::new ); <#elseif resultType.iterableType> <#if existingInstanceMapping || !canReturnImmediatelly> diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/common/Type.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/common/Type.ftl index ee7d0b106f..c039dda504 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/common/Type.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/common/Type.ftl @@ -12,6 +12,7 @@ <#elseif hasSuperBound()> ? super <@includeModel object=typeBound /> <#else> - <#if ext.asVarArgs!false>${createReferenceName()?remove_ending("[]")}...<#else>${createReferenceName()}<#if (!ext.raw?? && typeParameters?size > 0) ><<#list typeParameters as typeParameter><@includeModel object=typeParameter /><#if typeParameter_has_next>, > + <#assign createReferenceName = createReferenceName() /> + ${createReferenceName?keep_before("[]")}<#if (!ext.raw?? && typeParameters?size > 0) ><<#list typeParameters as typeParameter><@includeModel object=typeParameter /><#if typeParameter_has_next>, >${createReferenceName?keep_after("[]")}<#if ext.asVarArgs!false>...<#elseif isArrayType()>[] \ No newline at end of file diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/macro/CommonMacros.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/macro/CommonMacros.ftl index e0f3538c73..0599e8c0e4 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/macro/CommonMacros.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/macro/CommonMacros.ftl @@ -166,6 +166,12 @@ Performs a default assignment with a default value. <@constructTargetObject targetType=ext.targetType/> +<#-- +--> +<#macro constructArrayType targetType targetSize><@compress single_line=true> + <#assign targetTypeString><@includeModel object=targetType raw=true/> + new ${targetTypeString?keep_before("[")}[${targetSize}]${targetTypeString?keep_after("]")} + <#-- macro: constructTargetObject @@ -178,7 +184,7 @@ Performs a default assignment with a default value. <#if targetType.implementationType??> new <@includeModel object=targetType.implementationType raw=true/><#if targetType.implementationType.typeParameters?size != 0><>() <#elseif targetType.arrayType> - new <@includeModel object=targetType.componentType/>[0] + <@constructArrayType targetType=targetType targetSize=0/> <#elseif targetType.sensibleDefault??> ${targetType.sensibleDefault} <#elseif targetType.optionalType> diff --git a/processor/src/test/java/org/mapstruct/ap/test/array/ArrayMappingTest.java b/processor/src/test/java/org/mapstruct/ap/test/array/ArrayMappingTest.java index 67ef2216d8..fe33893417 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/array/ArrayMappingTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/array/ArrayMappingTest.java @@ -9,7 +9,9 @@ import java.util.List; import org.junit.jupiter.api.extension.RegisterExtension; +import org.mapstruct.ap.test.array._target.GenericScientistDto; import org.mapstruct.ap.test.array._target.ScientistDto; +import org.mapstruct.ap.test.array.source.GenericScientist; import org.mapstruct.ap.test.array.source.Scientist; import org.mapstruct.ap.testutil.IssueKey; import org.mapstruct.ap.testutil.ProcessorTest; @@ -18,7 +20,8 @@ import static org.assertj.core.api.Assertions.assertThat; -@WithClasses( { Scientist.class, ScientistDto.class, ScienceMapper.class } ) +@WithClasses( { Scientist.class, ScientistDto.class, GenericScientist.class, GenericScientistDto.class, + ScienceMapper.class } ) @IssueKey("108") public class ArrayMappingTest { @@ -56,30 +59,134 @@ public void shouldForgeMappingForIntToString() { } @ProcessorTest - public void shouldMapArrayToArray() { + public void shouldMapArrayToArrayAndNullToNull() { ScientistDto[] dtos = ScienceMapper.INSTANCE - .scientistsToDtos( new Scientist[]{ new Scientist( "Bob" ), new Scientist( "Larry" ) } ); + .scientistsToDtosReturnNull( new Scientist[]{ new Scientist( "Bob" ), new Scientist( "Larry" ) } ); assertThat( dtos ).isNotNull(); assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" ); + + assertThat( ScienceMapper.INSTANCE.scientistsToDtosReturnNull( (Scientist[]) null ) ).isNull(); + } + + @ProcessorTest + public void shouldMapArrayToArrayAndNullToDefault() { + ScientistDto[] dtos = ScienceMapper.INSTANCE + .scientistsToDtosReturnDefault( new Scientist[]{ new Scientist( "Bob" ), new Scientist( "Larry" ) } ); + + assertThat( dtos ).isNotNull(); + assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" ); + + assertThat( ScienceMapper.INSTANCE.scientistsToDtosReturnDefault( (Scientist[]) null ) ).isEmpty(); } @ProcessorTest - public void shouldMapListToArray() { + public void shouldMapListToArrayAndNullToNull() { ScientistDto[] dtos = ScienceMapper.INSTANCE - .scientistsToDtos( Arrays.asList( new Scientist( "Bob" ), new Scientist( "Larry" ) ) ); + .scientistsToDtosReturnNull( Arrays.asList( new Scientist( "Bob" ), new Scientist( "Larry" ) ) ); assertThat( dtos ).isNotNull(); assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" ); + + assertThat( ScienceMapper.INSTANCE.scientistsToDtosReturnNull( (List) null ) ).isNull(); } @ProcessorTest - public void shouldMapArrayToList() { + public void shouldMapListToArrayAndNullToDefault() { + ScientistDto[] dtos = ScienceMapper.INSTANCE + .scientistsToDtosReturnDefault( Arrays.asList( new Scientist( "Bob" ), new Scientist( "Larry" ) ) ); + + assertThat( dtos ).isNotNull(); + assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" ); + + assertThat( ScienceMapper.INSTANCE.scientistsToDtosReturnDefault( (List) null ) ).isEmpty(); + } + + @ProcessorTest + public void shouldMapArrayToListAndNullToNull() { List dtos = ScienceMapper.INSTANCE - .scientistsToDtosAsList( new Scientist[]{ new Scientist( "Bob" ), new Scientist( "Larry" ) } ); + .scientistsToDtosAsListReturnNull( new Scientist[]{ new Scientist( "Bob" ), new Scientist( "Larry" ) } ); + + assertThat( dtos ).isNotNull(); + assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" ); + + assertThat( ScienceMapper.INSTANCE.scientistsToDtosAsListReturnNull( null ) ).isNull(); + } + + @ProcessorTest + public void shouldMapArrayToListAndNullToDefault() { + List dtos = ScienceMapper.INSTANCE + .scientistsToDtosAsListReturnDefault( + new Scientist[]{ new Scientist( "Bob" ), new Scientist( "Larry" ) } ); + + assertThat( dtos ).isNotNull(); + assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" ); + + assertThat( ScienceMapper.INSTANCE.scientistsToDtosAsListReturnDefault( null ) ).isEmpty(); + } + + @ProcessorTest + @SuppressWarnings("unchecked") + public void shouldMapGenericArrayToGenericArrayAndNullToNull() { + GenericScientistDto[] dtos = ScienceMapper.INSTANCE + .genericScientistToDtosReturnNull( + new GenericScientist[]{ new GenericScientist<>( "Bob" ), new GenericScientist<>( "Larry" ) } ); + + assertThat( dtos ).isNotNull(); + assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" ); + + assertThat( ScienceMapper.INSTANCE.genericScientistToDtosReturnNull( (GenericScientist[]) null ) ) + .isNull(); + } + + @ProcessorTest + @SuppressWarnings("unchecked") + public void shouldMapGenericArrayToGenericArrayAndNullToDefault() { + GenericScientistDto[] dtos = ScienceMapper.INSTANCE.genericScientistToDtosReturnDefault( + new GenericScientist[]{ new GenericScientist<>( "Bob" ), new GenericScientist<>( "Larry" ) } ); + + assertThat( dtos ).isNotNull(); + assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" ); + + assertThat( ScienceMapper.INSTANCE.genericScientistToDtosReturnDefault( (GenericScientist[]) null ) ) + .isEmpty(); + } + + @ProcessorTest + public void shouldMapListToGenericArrayAndNullToNull() { + GenericScientistDto[] dtos = ScienceMapper.INSTANCE.genericScientistToDtosReturnNull( + Arrays.asList( new GenericScientist<>( "Bob" ), new GenericScientist<>( "Larry" ) ) ); assertThat( dtos ).isNotNull(); assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" ); + + assertThat( ScienceMapper.INSTANCE.genericScientistToDtosReturnNull( (List>) null ) ) + .isNull(); + } + + @ProcessorTest + public void shouldMapListToGenericArrayAndNullToDefault() { + GenericScientistDto[] dtos = ScienceMapper.INSTANCE + .genericScientistToDtosReturnDefault( + Arrays.asList( new GenericScientist<>("Bob"), new GenericScientist<>( "Larry" ) ) ); + + assertThat( dtos ).isNotNull(); + assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" ); + + assertThat( ScienceMapper.INSTANCE + .genericScientistToDtosReturnDefault( (List>) null ) ).isEmpty(); + } + + @ProcessorTest + @SuppressWarnings("unchecked") + public void shouldMapGenericArrayToListAndNullToNull() { + List> dtos = ScienceMapper.INSTANCE.genericScientistToDtosAsList( + new GenericScientist[]{ new GenericScientist<>( "Bob" ), new GenericScientist<>( "Larry" ) } ); + + assertThat( dtos ).isNotNull(); + assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" ); + + assertThat( ScienceMapper.INSTANCE.genericScientistToDtosAsList( null ) ).isNull(); } @ProcessorTest diff --git a/processor/src/test/java/org/mapstruct/ap/test/array/ScienceMapper.java b/processor/src/test/java/org/mapstruct/ap/test/array/ScienceMapper.java index b0dac0ea98..e90d92eb51 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/array/ScienceMapper.java +++ b/processor/src/test/java/org/mapstruct/ap/test/array/ScienceMapper.java @@ -11,7 +11,9 @@ import org.mapstruct.Mapper; import org.mapstruct.MappingTarget; import org.mapstruct.NullValueMappingStrategy; +import org.mapstruct.ap.test.array._target.GenericScientistDto; import org.mapstruct.ap.test.array._target.ScientistDto; +import org.mapstruct.ap.test.array.source.GenericScientist; import org.mapstruct.ap.test.array.source.Scientist; import org.mapstruct.factory.Mappers; @@ -22,14 +24,37 @@ public interface ScienceMapper { ScientistDto scientistToDto(Scientist scientist); - ScientistDto[] scientistsToDtos(Scientist[] scientists); + ScientistDto[] scientistsToDtosReturnNull(Scientist[] scientists); - ScientistDto[] scientistsToDtos(List scientists); + ScientistDto[] scientistsToDtosReturnNull(List scientists); - List scientistsToDtosAsList(Scientist[] scientists); + List scientistsToDtosAsListReturnNull(Scientist[] scientists); ScientistDto[] scientistsToDtos(Scientist[] scientists, @MappingTarget ScientistDto[] target); + @IterableMapping( nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT ) + ScientistDto[] scientistsToDtosReturnDefault(Scientist[] scientists); + + @IterableMapping( nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT ) + ScientistDto[] scientistsToDtosReturnDefault(List scientists); + + @IterableMapping( nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT ) + List scientistsToDtosAsListReturnDefault(Scientist[] scientists); + + GenericScientistDto genericScientistToDto(GenericScientist scientist); + + GenericScientistDto[] genericScientistToDtosReturnNull(GenericScientist[] genericScientist); + + GenericScientistDto[] genericScientistToDtosReturnNull(List> genericScientist); + + List> genericScientistToDtosAsList(GenericScientist[] genericScientist); + + @IterableMapping( nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT ) + GenericScientistDto[] genericScientistToDtosReturnDefault(GenericScientist[] genericScientist); + + @IterableMapping( nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT ) + GenericScientistDto[] genericScientistToDtosReturnDefault(List> genericScientist); + @IterableMapping(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT) boolean[] nvmMapping(boolean[] source); diff --git a/processor/src/test/java/org/mapstruct/ap/test/array/_target/GenericScientistDto.java b/processor/src/test/java/org/mapstruct/ap/test/array/_target/GenericScientistDto.java new file mode 100644 index 0000000000..ffab268e61 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/array/_target/GenericScientistDto.java @@ -0,0 +1,50 @@ +/* + * Copyright MapStruct Authors. + * + * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 + */ +package org.mapstruct.ap.test.array._target; + +public class GenericScientistDto { + + //CHECKSTYLE:OFF + public T[] publicPublications; + public int[] publicPublicationYears; + //CHECKSTYLE:ON + + private T name; + private T[] publications; + private int[] publicationYears; + + public GenericScientistDto() { + } + + public GenericScientistDto(T name) { + this.name = name; + } + + public T getName() { + return name; + } + + public void setName(T name) { + this.name = name; + } + + public T[] getPublications() { + return publications; + } + + public void setPublications(T[] publications) { + this.publications = publications; + } + + public int[] getPublicationYears() { + return publicationYears; + } + + public void setPublicationYears(int[] publicationYears) { + this.publicationYears = publicationYears; + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/array/source/GenericScientist.java b/processor/src/test/java/org/mapstruct/ap/test/array/source/GenericScientist.java new file mode 100644 index 0000000000..6a6f9a8cda --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/array/source/GenericScientist.java @@ -0,0 +1,46 @@ +/* + * Copyright MapStruct Authors. + * + * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 + */ +package org.mapstruct.ap.test.array.source; + +public class GenericScientist { + + //CHECKSTYLE:OFF + public T[] publicPublications; + public T[] publicPublicationYears; + //CHECKSTYLE:ON + private T name; + private T[] publications; + private T[] publicationYears; + + public GenericScientist(T name) { + this.name = name; + } + + public T getName() { + return name; + } + + public void setName(T name) { + this.name = name; + } + + public T[] getPublications() { + return publications; + } + + public void setPublications(T[] publications) { + this.publications = publications; + } + + public T[] getPublicationYears() { + return publicationYears; + } + + public void setPublicationYears(T[] publicationYears) { + this.publicationYears = publicationYears; + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_895/Issue895Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_895/Issue895Test.java index 320c7d1306..6250e139f2 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/bugs/_895/Issue895Test.java +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_895/Issue895Test.java @@ -6,7 +6,10 @@ package org.mapstruct.ap.test.bugs._895; import org.mapstruct.ap.test.bugs._895.MultiArrayMapper.WithArrayOfByteArray; +import org.mapstruct.ap.test.bugs._895.MultiArrayMapper.WithArrayOfGenericArray; import org.mapstruct.ap.test.bugs._895.MultiArrayMapper.WithListOfByteArray; +import org.mapstruct.ap.test.bugs._895.MultiArrayMapper.WithListOfGenericArray; +import org.mapstruct.ap.testutil.IssueKey; import org.mapstruct.ap.testutil.ProcessorTest; import org.mapstruct.ap.testutil.WithClasses; import org.mapstruct.factory.Mappers; @@ -14,10 +17,11 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Verifies that forged iterable mapping methods for multi-dimensional arrays are generated properly. + * Verifies that forged iterable mapping methods for multidimensional arrays are generated properly. * * @author Andreas Gudian */ +@IssueKey("895") @WithClasses(MultiArrayMapper.class) public class Issue895Test { @ProcessorTest @@ -31,4 +35,42 @@ public void properlyMapsMultiDimensionalArrays() { arrayOfByteArray = Mappers.getMapper( MultiArrayMapper.class ).convert( listOfByteArray ); assertThat( arrayOfByteArray.getBytes() ).isDeepEqualTo( new byte[][] { { 0, 1 }, { 1, 2 } } ); } + + @ProcessorTest + public void properlyMapsGenericMultiDimensionalArrays() { + WithArrayOfGenericArray arrayOfStringArray = new MultiArrayMapper.WithArrayOfGenericArray<>(); + arrayOfStringArray.setData( new String[][] { new String[] { "a", "b" }, new String[] { "b", "c" } } ); + + MultiArrayMapper mapper = Mappers.getMapper( MultiArrayMapper.class ); + WithListOfGenericArray listOfStringArray = mapper.convertGeneric( arrayOfStringArray ); + assertThat( listOfStringArray.getData() ) + .containsExactly( new String[] { "a", "b" }, new String[] { "b", "c" } ); + + arrayOfStringArray = mapper.convertGeneric( listOfStringArray ); + assertThat( arrayOfStringArray.getData() ) + .isDeepEqualTo( new String[][] { new String[] { "a", "b" }, new String[] { "b", "c" } } ); + } + + @ProcessorTest + public void properlyReturnDefaultForMultiArray() { + assertThat( Mappers.getMapper( MultiArrayMapper.class ).copyMultiArray( null ) ).isEmpty(); + } + + @ProcessorTest + @SuppressWarnings("unchecked") + public void properlyMapsGenericMultiArray() { + WithArrayOfGenericArray arrayOfGenericArray = new WithArrayOfGenericArray<>(); + arrayOfGenericArray.setData( new String[][] { new String[] { "a", "b" }, new String[] { "b", "c" } } ); + WithArrayOfGenericArray[][] multiArrayOfGenericArray = + new WithArrayOfGenericArray[][]{ new WithArrayOfGenericArray[]{ arrayOfGenericArray } }; + WithArrayOfGenericArray[][] result = + Mappers.getMapper( MultiArrayMapper.class ).copyGenericMultiArray( multiArrayOfGenericArray ); + assertThat( result ).isNotSameAs( multiArrayOfGenericArray ); + assertThat( result ).isDeepEqualTo( multiArrayOfGenericArray ); + } + + @ProcessorTest + public void properlyReturnDefaultForGenericMultiArray() { + assertThat( Mappers.getMapper( MultiArrayMapper.class ).copyGenericMultiArray( null ) ).isEmpty(); + } } diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_895/MultiArrayMapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_895/MultiArrayMapper.java index 7d01485e38..13a67125b8 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/bugs/_895/MultiArrayMapper.java +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_895/MultiArrayMapper.java @@ -7,7 +7,9 @@ import java.util.List; +import org.mapstruct.IterableMapping; import org.mapstruct.Mapper; +import org.mapstruct.NullValueMappingStrategy; /** * @author Andreas Gudian @@ -30,6 +32,16 @@ public void setBytes(byte[][] bytes) { } } + @IterableMapping(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT) + int[][] copyMultiArray(int[][] multiArray); + + WithListOfGenericArray convertGeneric(WithArrayOfGenericArray b); + + WithArrayOfGenericArray convertGeneric(WithListOfGenericArray b); + + @IterableMapping(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT) + WithArrayOfGenericArray[][] copyGenericMultiArray(WithArrayOfGenericArray[][] multiArray); + class WithListOfByteArray { private List bytes; @@ -41,4 +53,28 @@ public void setBytes(List bytes) { this.bytes = bytes; } } + + class WithArrayOfGenericArray { + private T [][] data; + + public T[][] getData() { + return data; + } + + public void setData(T[][] data) { + this.data = data; + } + } + + class WithListOfGenericArray { + private List data; + + public List getData() { + return data; + } + + public void setData(List data) { + this.data = data; + } + } } diff --git a/processor/src/test/java/org/mapstruct/ap/test/java8stream/Source.java b/processor/src/test/java/org/mapstruct/ap/test/java8stream/Source.java index da1198d3ef..feea09626c 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/java8stream/Source.java +++ b/processor/src/test/java/org/mapstruct/ap/test/java8stream/Source.java @@ -16,6 +16,10 @@ public class Source { private Stream integerStream; + private Stream integerStream2; + + private Stream integerArrayStream; + private Stream anotherIntegerStream; private Stream colours; @@ -24,6 +28,8 @@ public class Source { private Stream stringStream3; + private Stream> streamWithGenerics; + public Stream getStringStream() { return stringStream; } @@ -56,6 +62,22 @@ public void setIntegerStream(Stream integerStream) { this.integerStream = integerStream; } + public Stream getIntegerStream2() { + return integerStream2; + } + + public void setIntegerStream2(Stream integerStream2) { + this.integerStream2 = integerStream2; + } + + public Stream getIntegerArrayStream() { + return integerArrayStream; + } + + public void setIntegerArrayStream(Stream integerArrayStream) { + this.integerArrayStream = integerArrayStream; + } + public Stream getAnotherIntegerStream() { return anotherIntegerStream; } @@ -87,4 +109,12 @@ public Stream getStringStream3() { public void setStringStream3(Stream stringStream3) { this.stringStream3 = stringStream3; } + + public Stream> getStreamWithGenerics() { + return streamWithGenerics; + } + + public void setStreamWithGenerics(Stream> streamWithGenerics) { + this.streamWithGenerics = streamWithGenerics; + } } diff --git a/processor/src/test/java/org/mapstruct/ap/test/java8stream/SourceTargetMapper.java b/processor/src/test/java/org/mapstruct/ap/test/java8stream/SourceTargetMapper.java index 86d83844e8..089e3de156 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/java8stream/SourceTargetMapper.java +++ b/processor/src/test/java/org/mapstruct/ap/test/java8stream/SourceTargetMapper.java @@ -26,9 +26,12 @@ public abstract class SourceTargetMapper { @Mapping(target = "stringArrayList", source = "stringArrayStream"), @Mapping(target = "stringSet", source = "stringStreamToSet"), @Mapping(target = "integerCollection", source = "integerStream"), + @Mapping(target = "integerArray", source = "integerStream2"), + @Mapping(target = "integerMultiArray", source = "integerArrayStream"), @Mapping(target = "anotherStringSet", source = "anotherIntegerStream"), @Mapping(target = "stringListNoSetter", source = "stringStream2"), - @Mapping(target = "nonGenericStringList", source = "stringStream3") + @Mapping(target = "nonGenericStringList", source = "stringStream3"), + @Mapping(target = "arrayWithGenerics", source = "streamWithGenerics") }) public abstract Target sourceToTarget(Source source); diff --git a/processor/src/test/java/org/mapstruct/ap/test/java8stream/StreamMappingTest.java b/processor/src/test/java/org/mapstruct/ap/test/java8stream/StreamMappingTest.java index a15468e5e1..d62b1fc384 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/java8stream/StreamMappingTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/java8stream/StreamMappingTest.java @@ -225,4 +225,74 @@ public void shouldMapNonGenericList() { assertThat( mappedSource ).isNotNull(); assertThat( mappedSource.getStringStream3() ).containsExactly( "Bill", "Bob" ); } + + @ProcessorTest + public void shouldMapIntegerToIntegerArray() { + Source source = new Source(); + source.setIntegerStream2( Stream.of( 1, 2 ) ); + + Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source ); + + assertThat( target ).isNotNull(); + assertThat( target.getIntegerArray() ).containsExactly( 1, 2 ); + } + + @ProcessorTest + public void shouldReverseIntegerToIntegerArray() { + Target target = new Target(); + target.setIntegerArray( new Integer[]{ 1, 2 } ); + + Source source = SourceTargetMapper.INSTANCE.targetToSource( target ); + + assertThat( source ).isNotNull(); + assertThat( source.getIntegerStream2() ).containsExactly( 1, 2 ); + } + + @ProcessorTest + public void shouldMapIntegerArrayToIntegerMultiArray() { + Source source = new Source(); + source.setIntegerArrayStream( Stream.of( new Integer[]{ 1, 2 }, new Integer[]{ 2, 3 } ) ); + + Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source ); + + assertThat( target ).isNotNull(); + assertThat( target.getIntegerMultiArray() ) + .isDeepEqualTo( new Integer[][]{ new Integer[]{ 1, 2 }, new Integer[]{ 2, 3 } } ); + } + + @ProcessorTest + public void shouldReverseIntegerArrayToIntegerMultiArray() { + Target target = new Target(); + target.setIntegerMultiArray( new Integer[][]{ new Integer[]{ 1, 2 }, new Integer[]{ 2, 3 } } ); + + Source source = SourceTargetMapper.INSTANCE.targetToSource( target ); + + assertThat( source ).isNotNull(); + assertThat( source.getIntegerArrayStream() ).containsExactly( new Integer[]{ 1, 2 }, new Integer[]{ 2, 3 } ); + } + + @ProcessorTest + public void shouldMapTypeWithGenericsToArrayWithGenerics() { + Source source = new Source(); + Comparable comparable = o -> 0; + source.setStreamWithGenerics( Stream.of( comparable ) ); + + Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source ); + + assertThat( target ).isNotNull(); + assertThat( target.getArrayWithGenerics() ).containsExactly( comparable ); + } + + @ProcessorTest + @SuppressWarnings("unchecked") + public void shouldReverseMapTypeWithGenericsToArrayWithGenerics() { + Target target = new Target(); + Comparable comparable = o -> 0; + target.setArrayWithGenerics( new Comparable[]{ comparable } ); + + Source source = SourceTargetMapper.INSTANCE.targetToSource( target ); + + assertThat( source ).isNotNull(); + assertThat( source.getStreamWithGenerics() ).containsExactly( comparable ); + } } diff --git a/processor/src/test/java/org/mapstruct/ap/test/java8stream/Target.java b/processor/src/test/java/org/mapstruct/ap/test/java8stream/Target.java index 49b23530df..91d9e89908 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/java8stream/Target.java +++ b/processor/src/test/java/org/mapstruct/ap/test/java8stream/Target.java @@ -27,6 +27,12 @@ public class Target { private StringHolderArrayList nonGenericStringList; + private Integer[] integerArray; + + private Integer[][] integerMultiArray; + + private Comparable[] arrayWithGenerics; + public List getStringList() { return stringList; } @@ -89,4 +95,28 @@ public StringHolderArrayList getNonGenericStringList() { public void setNonGenericStringList(StringHolderArrayList nonGenericStringList) { this.nonGenericStringList = nonGenericStringList; } + + public Integer[] getIntegerArray() { + return integerArray; + } + + public void setIntegerArray(Integer[] integerArray) { + this.integerArray = integerArray; + } + + public Integer[][] getIntegerMultiArray() { + return integerMultiArray; + } + + public void setIntegerMultiArray(Integer[][] integerMultiArray) { + this.integerMultiArray = integerMultiArray; + } + + public Comparable[] getArrayWithGenerics() { + return arrayWithGenerics; + } + + public void setArrayWithGenerics(Comparable[] arrayWithGenerics) { + this.arrayWithGenerics = arrayWithGenerics; + } } 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 6237606b88..f0d13a77c4 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 @@ -10,7 +10,9 @@ import java.util.Arrays; import java.util.List; import javax.annotation.Generated; +import org.mapstruct.ap.test.array._target.GenericScientistDto; import org.mapstruct.ap.test.array._target.ScientistDto; +import org.mapstruct.ap.test.array.source.GenericScientist; import org.mapstruct.ap.test.array.source.Scientist; @Generated( @@ -44,7 +46,7 @@ public ScientistDto scientistToDto(Scientist scientist) { } @Override - public ScientistDto[] scientistsToDtos(Scientist[] scientists) { + public ScientistDto[] scientistsToDtosReturnNull(Scientist[] scientists) { if ( scientists == null ) { return null; } @@ -60,7 +62,7 @@ public ScientistDto[] scientistsToDtos(Scientist[] scientists) { } @Override - public ScientistDto[] scientistsToDtos(List scientists) { + public ScientistDto[] scientistsToDtosReturnNull(List scientists) { if ( scientists == null ) { return null; } @@ -76,7 +78,7 @@ public ScientistDto[] scientistsToDtos(List scientists) { } @Override - public List scientistsToDtosAsList(Scientist[] scientists) { + public List scientistsToDtosAsListReturnNull(Scientist[] scientists) { if ( scientists == null ) { return null; } @@ -107,6 +109,153 @@ public ScientistDto[] scientistsToDtos(Scientist[] scientists, ScientistDto[] ta return target; } + @Override + public ScientistDto[] scientistsToDtosReturnDefault(Scientist[] scientists) { + if ( scientists == null ) { + return new ScientistDto[0]; + } + + ScientistDto[] scientistDtoTmp = new ScientistDto[scientists.length]; + int i = 0; + for ( Scientist scientist : scientists ) { + scientistDtoTmp[i] = scientistToDto( scientist ); + i++; + } + + return scientistDtoTmp; + } + + @Override + public ScientistDto[] scientistsToDtosReturnDefault(List scientists) { + if ( scientists == null ) { + return new ScientistDto[0]; + } + + ScientistDto[] scientistDtoTmp = new ScientistDto[scientists.size()]; + int i = 0; + for ( Scientist scientist : scientists ) { + scientistDtoTmp[i] = scientistToDto( scientist ); + i++; + } + + return scientistDtoTmp; + } + + @Override + public List scientistsToDtosAsListReturnDefault(Scientist[] scientists) { + if ( scientists == null ) { + return new ArrayList<>(); + } + + List list = new ArrayList<>( scientists.length ); + for ( Scientist scientist : scientists ) { + list.add( scientistToDto( scientist ) ); + } + + return list; + } + + @Override + public GenericScientistDto genericScientistToDto(GenericScientist scientist) { + if ( scientist == null ) { + return null; + } + + GenericScientistDto genericScientistDto = new GenericScientistDto<>(); + + genericScientistDto.setName( scientist.getName() ); + String[] publications = scientist.getPublications(); + if ( publications != null ) { + genericScientistDto.setPublications( Arrays.copyOf( publications, publications.length ) ); + } + genericScientistDto.setPublicationYears( stringArrayTointArray( scientist.getPublicationYears() ) ); + String[] publicPublications = scientist.publicPublications; + if ( publicPublications != null ) { + genericScientistDto.publicPublications = Arrays.copyOf( publicPublications, publicPublications.length ); + } + genericScientistDto.publicPublicationYears = stringArrayTointArray( scientist.publicPublicationYears ); + + return genericScientistDto; + } + + @Override + public GenericScientistDto[] genericScientistToDtosReturnNull(GenericScientist[] genericScientist) { + if ( genericScientist == null ) { + return null; + } + + GenericScientistDto[] genericScientistDtoTmp = new GenericScientistDto[genericScientist.length]; + int i = 0; + for ( GenericScientist genericScientist1 : genericScientist ) { + genericScientistDtoTmp[i] = genericScientistToDto( genericScientist1 ); + i++; + } + + return genericScientistDtoTmp; + } + + @Override + public GenericScientistDto[] genericScientistToDtosReturnNull(List> genericScientist) { + if ( genericScientist == null ) { + return null; + } + + GenericScientistDto[] genericScientistDtoTmp = new GenericScientistDto[genericScientist.size()]; + int i = 0; + for ( GenericScientist genericScientist1 : genericScientist ) { + genericScientistDtoTmp[i] = genericScientistToDto( genericScientist1 ); + i++; + } + + return genericScientistDtoTmp; + } + + @Override + public List> genericScientistToDtosAsList(GenericScientist[] genericScientist) { + if ( genericScientist == null ) { + return null; + } + + List> list = new ArrayList<>( genericScientist.length ); + for ( GenericScientist genericScientist1 : genericScientist ) { + list.add( genericScientistToDto( genericScientist1 ) ); + } + + return list; + } + + @Override + public GenericScientistDto[] genericScientistToDtosReturnDefault(GenericScientist[] genericScientist) { + if ( genericScientist == null ) { + return new GenericScientistDto[0]; + } + + GenericScientistDto[] genericScientistDtoTmp = new GenericScientistDto[genericScientist.length]; + int i = 0; + for ( GenericScientist genericScientist1 : genericScientist ) { + genericScientistDtoTmp[i] = genericScientistToDto( genericScientist1 ); + i++; + } + + return genericScientistDtoTmp; + } + + @Override + public GenericScientistDto[] genericScientistToDtosReturnDefault(List> genericScientist) { + if ( genericScientist == null ) { + return new GenericScientistDto[0]; + } + + GenericScientistDto[] genericScientistDtoTmp = new GenericScientistDto[genericScientist.size()]; + int i = 0; + for ( GenericScientist genericScientist1 : genericScientist ) { + genericScientistDtoTmp[i] = genericScientistToDto( genericScientist1 ); + i++; + } + + return genericScientistDtoTmp; + } + @Override public boolean[] nvmMapping(boolean[] source) { if ( source == null ) { From 779b2b993d8d9327558f093112f93f8b8afadaa1 Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Thu, 14 May 2026 08:48:14 +0200 Subject: [PATCH 2/3] polish --- .../ap/internal/model/common/Type.java | 181 +++++++----------- .../ap/test/array/ScienceMapper.java | 10 +- .../ap/test/array/ScienceMapperImpl.java | 50 ++--- 3 files changed, 104 insertions(+), 137 deletions(-) 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 37cefbed83..3017a2fac6 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 @@ -697,66 +697,49 @@ public Type replaceSuperBoundWith( Type compare, Type replacement ) { return this; } + TypeElement typeElementWithoutBounds; + Type componentTypeWithoutBounds; + TypeMirror typeMirrorWithoutBounds; if ( this.componentType != null ) { - Type componentTypeWithoutBounds = this.componentType.replaceSuperBoundWith( compare, replacement ); - - return new Type( - typeUtils, - elementUtils, - typeFactory, - accessorNaming, - typeUtils.getArrayType( componentTypeWithoutBounds.getTypeMirror() ), - null, - bounds, - implementationType, - componentTypeWithoutBounds, - packageName, - name, - qualifiedName, - isInterface, - isEnumType, - isIterableType, - isCollectionType, - isMapType, - isStream, - toBeImportedTypes, - notToBeImportedTypes, - isToBeImported, - isLiteral, - loggingVerbose - ); + typeElementWithoutBounds = null; + componentTypeWithoutBounds = this.componentType.replaceSuperBoundWith( compare, replacement ); + typeMirrorWithoutBounds = typeUtils.getArrayType( componentTypeWithoutBounds.getTypeMirror() ); } else { DeclaredType declaredType = typeUtils.getDeclaredType( - typeElement, - mirrors - ); - return new Type( - typeUtils, - elementUtils, - typeFactory, - accessorNaming, - declaredType, - (TypeElement) declaredType.asElement(), - bounds, - implementationType, - componentType, - packageName, - name, - qualifiedName, - isInterface, - isEnumType, - isIterableType, - isCollectionType, - isMapType, - isStream, - toBeImportedTypes, - notToBeImportedTypes, - isToBeImported, - isLiteral, - loggingVerbose + typeElement, + mirrors ); + typeMirrorWithoutBounds = declaredType; + typeElementWithoutBounds = (TypeElement) declaredType.asElement(); + componentTypeWithoutBounds = null; } + + return new Type( + typeUtils, + elementUtils, + typeFactory, + accessorNaming, + typeMirrorWithoutBounds, + typeElementWithoutBounds, + bounds, + implementationType, + componentTypeWithoutBounds, + packageName, + name, + qualifiedName, + isInterface, + isEnumType, + isIterableType, + isCollectionType, + isMapType, + isStream, + toBeImportedTypes, + notToBeImportedTypes, + isToBeImported, + isLiteral, + loggingVerbose + ); } public Type withoutBounds() { @@ -771,65 +754,49 @@ public Type withoutBounds() { mirrors.add( typeParameter.getTypeBound().getTypeMirror() ); } + TypeElement typeElementWithoutBounds; + Type componentTypeWithoutBounds; + TypeMirror typeMirrorWithoutBounds; if ( this.componentType != null ) { - Type componentTypeWithoutBounds = this.componentType.withoutBounds(); - - return new Type( - typeUtils, - elementUtils, - typeFactory, - accessorNaming, - typeUtils.getArrayType( componentTypeWithoutBounds.getTypeMirror() ), - null, - bounds, - implementationType, - componentTypeWithoutBounds, - packageName, - name, - qualifiedName, - isInterface, - isEnumType, - isIterableType, - isCollectionType, - isMapType, - isStream, - toBeImportedTypes, - notToBeImportedTypes, - isToBeImported, - isLiteral, - loggingVerbose - ); + typeElementWithoutBounds = null; + componentTypeWithoutBounds = this.componentType.withoutBounds(); + typeMirrorWithoutBounds = typeUtils.getArrayType( componentTypeWithoutBounds.getTypeMirror() ); } else { DeclaredType declaredType = typeUtils.getDeclaredType( - typeElement, - mirrors.toArray( new TypeMirror[] {} ) ); - return new Type( - typeUtils, - elementUtils, - typeFactory, - accessorNaming, - declaredType, - (TypeElement) declaredType.asElement(), - bounds, - implementationType, - null, - packageName, - name, - qualifiedName, - isInterface, - isEnumType, - isIterableType, - isCollectionType, - isMapType, - isStream, - toBeImportedTypes, - notToBeImportedTypes, - isToBeImported, - isLiteral, - loggingVerbose + typeElement, + mirrors.toArray( new TypeMirror[] {} ) ); + typeMirrorWithoutBounds = declaredType; + typeElementWithoutBounds = (TypeElement) declaredType.asElement(); + componentTypeWithoutBounds = null; } + + return new Type( + typeUtils, + elementUtils, + typeFactory, + accessorNaming, + typeMirrorWithoutBounds, + typeElementWithoutBounds, + bounds, + implementationType, + componentTypeWithoutBounds, + packageName, + name, + qualifiedName, + isInterface, + isEnumType, + isIterableType, + isCollectionType, + isMapType, + isStream, + toBeImportedTypes, + notToBeImportedTypes, + isToBeImported, + isLiteral, + loggingVerbose + ); } private Type replaceGeneric(Type oldGenericType, Type newType) { diff --git a/processor/src/test/java/org/mapstruct/ap/test/array/ScienceMapper.java b/processor/src/test/java/org/mapstruct/ap/test/array/ScienceMapper.java index e90d92eb51..125dc94c9f 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/array/ScienceMapper.java +++ b/processor/src/test/java/org/mapstruct/ap/test/array/ScienceMapper.java @@ -43,17 +43,17 @@ public interface ScienceMapper { GenericScientistDto genericScientistToDto(GenericScientist scientist); - GenericScientistDto[] genericScientistToDtosReturnNull(GenericScientist[] genericScientist); + GenericScientistDto[] genericScientistToDtosReturnNull(GenericScientist[] genericScientists); - GenericScientistDto[] genericScientistToDtosReturnNull(List> genericScientist); + GenericScientistDto[] genericScientistToDtosReturnNull(List> genericScientists); - List> genericScientistToDtosAsList(GenericScientist[] genericScientist); + List> genericScientistToDtosAsList(GenericScientist[] genericScientists); @IterableMapping( nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT ) - GenericScientistDto[] genericScientistToDtosReturnDefault(GenericScientist[] genericScientist); + GenericScientistDto[] genericScientistToDtosReturnDefault(GenericScientist[] genericScientists); @IterableMapping( nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT ) - GenericScientistDto[] genericScientistToDtosReturnDefault(List> genericScientist); + GenericScientistDto[] genericScientistToDtosReturnDefault(List> genericScientists); @IterableMapping(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT) boolean[] nvmMapping(boolean[] source); 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 f0d13a77c4..21c7d71367 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 @@ -179,15 +179,15 @@ public GenericScientistDto genericScientistToDto(GenericScientist[] genericScientistToDtosReturnNull(GenericScientist[] genericScientist) { - if ( genericScientist == null ) { + public GenericScientistDto[] genericScientistToDtosReturnNull(GenericScientist[] genericScientists) { + if ( genericScientists == null ) { return null; } - GenericScientistDto[] genericScientistDtoTmp = new GenericScientistDto[genericScientist.length]; + GenericScientistDto[] genericScientistDtoTmp = new GenericScientistDto[genericScientists.length]; int i = 0; - for ( GenericScientist genericScientist1 : genericScientist ) { - genericScientistDtoTmp[i] = genericScientistToDto( genericScientist1 ); + for ( GenericScientist genericScientist : genericScientists ) { + genericScientistDtoTmp[i] = genericScientistToDto( genericScientist ); i++; } @@ -195,15 +195,15 @@ public GenericScientistDto[] genericScientistToDtosReturnNull(GenericSci } @Override - public GenericScientistDto[] genericScientistToDtosReturnNull(List> genericScientist) { - if ( genericScientist == null ) { + public GenericScientistDto[] genericScientistToDtosReturnNull(List> genericScientists) { + if ( genericScientists == null ) { return null; } - GenericScientistDto[] genericScientistDtoTmp = new GenericScientistDto[genericScientist.size()]; + GenericScientistDto[] genericScientistDtoTmp = new GenericScientistDto[genericScientists.size()]; int i = 0; - for ( GenericScientist genericScientist1 : genericScientist ) { - genericScientistDtoTmp[i] = genericScientistToDto( genericScientist1 ); + for ( GenericScientist genericScientist : genericScientists ) { + genericScientistDtoTmp[i] = genericScientistToDto( genericScientist ); i++; } @@ -211,29 +211,29 @@ public GenericScientistDto[] genericScientistToDtosReturnNull(List> genericScientistToDtosAsList(GenericScientist[] genericScientist) { - if ( genericScientist == null ) { + public List> genericScientistToDtosAsList(GenericScientist[] genericScientists) { + if ( genericScientists == null ) { return null; } - List> list = new ArrayList<>( genericScientist.length ); - for ( GenericScientist genericScientist1 : genericScientist ) { - list.add( genericScientistToDto( genericScientist1 ) ); + List> list = new ArrayList<>( genericScientists.length ); + for ( GenericScientist genericScientist : genericScientists ) { + list.add( genericScientistToDto( genericScientist ) ); } return list; } @Override - public GenericScientistDto[] genericScientistToDtosReturnDefault(GenericScientist[] genericScientist) { - if ( genericScientist == null ) { + public GenericScientistDto[] genericScientistToDtosReturnDefault(GenericScientist[] genericScientists) { + if ( genericScientists == null ) { return new GenericScientistDto[0]; } - GenericScientistDto[] genericScientistDtoTmp = new GenericScientistDto[genericScientist.length]; + GenericScientistDto[] genericScientistDtoTmp = new GenericScientistDto[genericScientists.length]; int i = 0; - for ( GenericScientist genericScientist1 : genericScientist ) { - genericScientistDtoTmp[i] = genericScientistToDto( genericScientist1 ); + for ( GenericScientist genericScientist : genericScientists ) { + genericScientistDtoTmp[i] = genericScientistToDto( genericScientist ); i++; } @@ -241,15 +241,15 @@ public GenericScientistDto[] genericScientistToDtosReturnDefault(Generic } @Override - public GenericScientistDto[] genericScientistToDtosReturnDefault(List> genericScientist) { - if ( genericScientist == null ) { + public GenericScientistDto[] genericScientistToDtosReturnDefault(List> genericScientists) { + if ( genericScientists == null ) { return new GenericScientistDto[0]; } - GenericScientistDto[] genericScientistDtoTmp = new GenericScientistDto[genericScientist.size()]; + GenericScientistDto[] genericScientistDtoTmp = new GenericScientistDto[genericScientists.size()]; int i = 0; - for ( GenericScientist genericScientist1 : genericScientist ) { - genericScientistDtoTmp[i] = genericScientistToDto( genericScientist1 ); + for ( GenericScientist genericScientist : genericScientists ) { + genericScientistDtoTmp[i] = genericScientistToDto( genericScientist ); i++; } From a9969a4771d97060e81165943697c18542258c6e Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Thu, 14 May 2026 09:00:52 +0200 Subject: [PATCH 3/3] fix whitespace --- .../ap/internal/model/common/Type.java | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) 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 3017a2fac6..5a45cb33cf 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 @@ -773,29 +773,29 @@ public Type withoutBounds() { } return new Type( - typeUtils, - elementUtils, - typeFactory, - accessorNaming, - typeMirrorWithoutBounds, - typeElementWithoutBounds, - bounds, - implementationType, - componentTypeWithoutBounds, - packageName, - name, - qualifiedName, - isInterface, - isEnumType, - isIterableType, - isCollectionType, - isMapType, - isStream, - toBeImportedTypes, - notToBeImportedTypes, - isToBeImported, - isLiteral, - loggingVerbose + typeUtils, + elementUtils, + typeFactory, + accessorNaming, + typeMirrorWithoutBounds, + typeElementWithoutBounds, + bounds, + implementationType, + componentTypeWithoutBounds, + packageName, + name, + qualifiedName, + isInterface, + isEnumType, + isIterableType, + isCollectionType, + isMapType, + isStream, + toBeImportedTypes, + notToBeImportedTypes, + isToBeImported, + isLiteral, + loggingVerbose ); }