From 30651b989bd15424d46b49edaf258a1b311ff9ee Mon Sep 17 00:00:00 2001 From: thunderhook <8238759+thunderhook@users.noreply.github.com> Date: Fri, 20 Sep 2024 23:29:37 +0200 Subject: [PATCH 1/3] highly WIP --- .../java/org/mapstruct/ConditionStrategy.java | 4 ++ .../mapstruct/IterableElementCondition.java | 25 ++++++++ .../ap/internal/gem/ConditionStrategyGem.java | 3 +- .../model/source/ConditionOptions.java | 3 + .../internal/model/IterableMappingMethod.ftl | 6 +- .../IterableElementConditionMapper.java | 37 ++++++++++++ .../IterableElementConditionTest.java | 59 +++++++++++++++++++ 7 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 core/src/main/java/org/mapstruct/IterableElementCondition.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/conditional/iterable/IterableElementConditionMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/conditional/iterable/IterableElementConditionTest.java diff --git a/core/src/main/java/org/mapstruct/ConditionStrategy.java b/core/src/main/java/org/mapstruct/ConditionStrategy.java index 6b042017c2..d0a06cf8f7 100644 --- a/core/src/main/java/org/mapstruct/ConditionStrategy.java +++ b/core/src/main/java/org/mapstruct/ConditionStrategy.java @@ -20,4 +20,8 @@ public enum ConditionStrategy { * The condition method should be applied to check if a source parameters should be mapped. */ SOURCE_PARAMETERS, + /** + * The condition method should be applied whether an element should be added to the iterable target. + */ + ITERABLE_ELEMENTS, } diff --git a/core/src/main/java/org/mapstruct/IterableElementCondition.java b/core/src/main/java/org/mapstruct/IterableElementCondition.java new file mode 100644 index 0000000000..491d47a64c --- /dev/null +++ b/core/src/main/java/org/mapstruct/IterableElementCondition.java @@ -0,0 +1,25 @@ +/* + * Copyright MapStruct Authors. + * + * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 + */ +package org.mapstruct; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * FIXME + * + * @author Oliver Erhart + * @since 1.7 + * @see Condition @Condition + */ +@Target({ ElementType.METHOD }) +@Retention(RetentionPolicy.CLASS) +@Condition(appliesTo = ConditionStrategy.ITERABLE_ELEMENTS) +public @interface IterableElementCondition { + +} diff --git a/processor/src/main/java/org/mapstruct/ap/internal/gem/ConditionStrategyGem.java b/processor/src/main/java/org/mapstruct/ap/internal/gem/ConditionStrategyGem.java index adea4b4c1f..e9432cafd4 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/gem/ConditionStrategyGem.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/gem/ConditionStrategyGem.java @@ -11,5 +11,6 @@ public enum ConditionStrategyGem { PROPERTIES, - SOURCE_PARAMETERS + SOURCE_PARAMETERS, + ITERABLE_ELEMENTS } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/ConditionOptions.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/ConditionOptions.java index 936d049af8..3140982f99 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/ConditionOptions.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/ConditionOptions.java @@ -93,6 +93,9 @@ protected static boolean isValid(ConditionStrategyGem strategy, ConditionGem con else if ( strategy == ConditionStrategyGem.PROPERTIES ) { return hasValidStrategyForProperties( condition, method, parameters, messager ); } + else if ( strategy == ConditionStrategyGem.ITERABLE_ELEMENTS ) { + return true; + } else { throw new IllegalStateException( "Invalid condition strategy: " + strategy ); } 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 4d08c44b38..ead8b4c247 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 @@ -24,7 +24,7 @@ <#if resultType.arrayType> <#if existingInstanceMapping> <#-- we can't clear an existing array, so we've got to clear by setting values to default --> - for (int ${index2Name} = 0; ${index2Name} < ${resultName}.length; ${index2Name}++ ) { + // test ${resultName}[${index2Name}] = ${resultElementType.null}; } return<#if returnType.name != "void"> ${resultName}; @@ -74,7 +74,9 @@ } <#else> for ( <@includeModel object=sourceElementType/> ${loopVariableName} : ${sourceParameter.name} ) { - <@includeModel object=elementAssignment targetBeanName=resultName targetWriteAccessorName="add" targetType=resultElementType/> + if ( countryIsNotNull( employeeDto ) ) { + <@includeModel object=elementAssignment targetBeanName=resultName targetWriteAccessorName="add" targetType=resultElementType/> + } } <#list afterMappingReferences as callback> diff --git a/processor/src/test/java/org/mapstruct/ap/test/conditional/iterable/IterableElementConditionMapper.java b/processor/src/test/java/org/mapstruct/ap/test/conditional/iterable/IterableElementConditionMapper.java new file mode 100644 index 0000000000..5e564a1d88 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/conditional/iterable/IterableElementConditionMapper.java @@ -0,0 +1,37 @@ +/* + * 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.conditional.iterable; + +import java.util.List; + +import org.mapstruct.IterableElementCondition; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.ap.test.conditional.Employee; +import org.mapstruct.ap.test.conditional.EmployeeDto; +import org.mapstruct.factory.Mappers; + +/** + * @author Oliver Erhart + */ +@Mapper +public interface IterableElementConditionMapper { + + IterableElementConditionMapper INSTANCE = + Mappers.getMapper( IterableElementConditionMapper.class ); + + @Mapping(target = "nin", source = "name") + @Mapping(target = "ssid", source = "uniqueIdNumber") + Employee map(EmployeeDto employee); + + List map(List employees); + + @IterableElementCondition + default boolean countryIsNotNull(EmployeeDto value) { + return value.getCountry() != null; + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/conditional/iterable/IterableElementConditionTest.java b/processor/src/test/java/org/mapstruct/ap/test/conditional/iterable/IterableElementConditionTest.java new file mode 100644 index 0000000000..1fcb81e04f --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/conditional/iterable/IterableElementConditionTest.java @@ -0,0 +1,59 @@ +/* + * 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.conditional.iterable; + +import java.util.ArrayList; +import java.util.List; + +import org.mapstruct.ap.test.conditional.Employee; +import org.mapstruct.ap.test.conditional.EmployeeDto; +import org.mapstruct.ap.testutil.IssueKey; +import org.mapstruct.ap.testutil.ProcessorTest; +import org.mapstruct.ap.testutil.WithClasses; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Oliver Erhart + */ +@IssueKey("1610") +@WithClasses({ + Employee.class, + EmployeeDto.class +}) +public class IterableElementConditionTest { + + @ProcessorTest + @WithClasses({ + IterableElementConditionMapper.class + }) + public void conditionalMethodWithSourceParameter() { + IterableElementConditionMapper mapper = IterableElementConditionMapper.INSTANCE; + + EmployeeDto dtoWithoutCountry = new EmployeeDto(); + dtoWithoutCountry.setName( "Tester" ); + dtoWithoutCountry.setUniqueIdNumber( "SSID-001" ); + dtoWithoutCountry.setCountry( null ); + + EmployeeDto dtoWithCountry = new EmployeeDto(); + dtoWithCountry.setName( "Tester" ); + dtoWithCountry.setUniqueIdNumber( "SSID-001" ); + dtoWithCountry.setCountry( "Austria" ); + + ArrayList employees = new ArrayList<>(); + employees.add( dtoWithoutCountry ); + employees.add( dtoWithCountry ); + + List result = mapper.map( employees ); + assertThat( result ) + .singleElement() + .satisfies( + d -> assertThat(d.getName()).isEqualTo( "Tester" ) + ); + + } + +} From d9566bab76e1bf56b9fd476430e9ec112b0f0847 Mon Sep 17 00:00:00 2001 From: thunderhook <8238759+thunderhook@users.noreply.github.com> Date: Sun, 22 Sep 2024 22:24:10 +0200 Subject: [PATCH 2/3] highly WIP --- .../internal/model/IterableMappingMethod.java | 46 +++++++++++++++++-- .../processor/MapperCreationProcessor.java | 9 ++++ .../internal/model/IterableMappingMethod.ftl | 9 ++-- 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/IterableMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/internal/model/IterableMappingMethod.java index 10e64b7008..dd375b5025 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/IterableMappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/IterableMappingMethod.java @@ -5,8 +5,7 @@ */ package org.mapstruct.ap.internal.model; -import static org.mapstruct.ap.internal.util.Collections.first; - +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; @@ -14,10 +13,13 @@ import org.mapstruct.ap.internal.model.assignment.LocalVarWrapper; import org.mapstruct.ap.internal.model.assignment.SetterWrapper; import org.mapstruct.ap.internal.model.common.Assignment; +import org.mapstruct.ap.internal.model.common.ParameterBinding; import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.source.Method; import org.mapstruct.ap.internal.model.source.SelectionParameters; +import static org.mapstruct.ap.internal.util.Collections.first; + /** * A {@link MappingMethod} implemented by a {@link Mapper} class which maps one iterable type to another. The collection * elements are mapped either by a {@link TypeConversion} or another mapping method. @@ -26,12 +28,21 @@ */ public class IterableMappingMethod extends ContainerMappingMethod { + private Method iterableConditionMethod; + public static class Builder extends ContainerMappingMethodBuilder { + private Method iterableConditionMethod; + public Builder() { super( Builder.class, "collection element" ); } + public Builder iterableConditionMethod(Method iterableConditionMethod) { + this.iterableConditionMethod = iterableConditionMethod; + return this; + } + @Override protected Type getElementType(Type parameterType) { return parameterType.isArrayType() ? parameterType.getComponentType() : first( @@ -65,17 +76,43 @@ protected IterableMappingMethod instantiateMappingMethod(Method method, Collecti loopVariableName, beforeMappingMethods, afterMappingMethods, - selectionParameters + selectionParameters, + iterableConditionMethod ); } } + public boolean hasIterableConditionMethod() { + return getIterableConditionMethod() != null; + } + + public Method getIterableConditionMethod() { + return iterableConditionMethod; + } + + public MethodReference getIterableConditionMethodReference() { + + ArrayList parameterBindings = new ArrayList<>(); + + parameterBindings.add( + ParameterBinding.fromTypeAndName( + iterableConditionMethod.getParameters().get( 0 ).getType(), + getLoopVariableName() + ) + ); + + return MethodReference.forForgedMethod( + iterableConditionMethod, + parameterBindings + ); + } + private IterableMappingMethod(Method method, List annotations, Collection existingVariables, Assignment parameterAssignment, MethodReference factoryMethod, boolean mapNullToDefault, String loopVariableName, List beforeMappingReferences, List afterMappingReferences, - SelectionParameters selectionParameters) { + SelectionParameters selectionParameters, Method iterableConditionMethod) { super( method, annotations, @@ -88,6 +125,7 @@ private IterableMappingMethod(Method method, List annotations, afterMappingReferences, selectionParameters ); + this.iterableConditionMethod = iterableConditionMethod; } @Override diff --git a/processor/src/main/java/org/mapstruct/ap/internal/processor/MapperCreationProcessor.java b/processor/src/main/java/org/mapstruct/ap/internal/processor/MapperCreationProcessor.java index 5fc1b07823..debaea36fe 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/processor/MapperCreationProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/processor/MapperCreationProcessor.java @@ -25,6 +25,7 @@ import javax.lang.model.util.ElementFilter; import org.mapstruct.ap.internal.gem.BuilderGem; +import org.mapstruct.ap.internal.gem.ConditionStrategyGem; import org.mapstruct.ap.internal.gem.DecoratedWithGem; import org.mapstruct.ap.internal.gem.InheritConfigurationGem; import org.mapstruct.ap.internal.gem.InheritInverseConfigurationGem; @@ -340,10 +341,18 @@ private List getMappingMethods(MapperOptions mapperAnnotation, Li this.messager.note( 1, Message.ITERABLEMAPPING_CREATE_NOTE, method ); + Method iterableConditionMethod = methods.stream() + .filter( m -> m.getConditionOptions() + .isStrategyApplicable( ConditionStrategyGem.ITERABLE_ELEMENTS ) ) + .findFirst() + .orElse( null ); + + // TODO here are all methods - select them via MethodResolver (like PresenceCheckMethodResolver) and add it to the builder IterableMappingMethod iterableMappingMethod = createWithElementMappingMethod( method, mappingOptions, new IterableMappingMethod.Builder() + .iterableConditionMethod( iterableConditionMethod ) ); hasFactoryMethod = iterableMappingMethod.getFactoryMethod() != null; 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 ead8b4c247..adc4005d8b 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 @@ -24,7 +24,6 @@ <#if resultType.arrayType> <#if existingInstanceMapping> <#-- we can't clear an existing array, so we've got to clear by setting values to default --> - // test ${resultName}[${index2Name}] = ${resultElementType.null}; } return<#if returnType.name != "void"> ${resultName}; @@ -74,9 +73,13 @@ } <#else> for ( <@includeModel object=sourceElementType/> ${loopVariableName} : ${sourceParameter.name} ) { - if ( countryIsNotNull( employeeDto ) ) { + <#if hasIterableConditionMethod()> + if ( <@includeModel object=iterableConditionMethodReference /> ) { <@includeModel object=elementAssignment targetBeanName=resultName targetWriteAccessorName="add" targetType=resultElementType/> - } + } + <#else> + <@includeModel object=elementAssignment targetBeanName=resultName targetWriteAccessorName="add" targetType=resultElementType/> + } <#list afterMappingReferences as callback> From 728b42ac2582ecd29682bda1ba3042f27ad77862 Mon Sep 17 00:00:00 2001 From: thunderhook <8238759+thunderhook@users.noreply.github.com> Date: Sun, 22 Sep 2024 23:12:33 +0200 Subject: [PATCH 3/3] tried to support arrays as target - stopped because of null values in target array - intermediate method used for lists and then `resultList.toArray(new Employee[0]);` would be nice - or somehow using a list in the forged method anyways: ``` public Employee[] mapListToArray(List employees) { if (employees == null) { return null; } List resultList = new ArrayList<>(); for ( EmployeeDto employeeDto : employees ) { if ( countryIsNotNull( employeeDto ) ) { resultList.add(map(employeeDto)); } } return resultList.toArray(new Employee[0]); } ``` --- .../internal/model/IterableMappingMethod.java | 11 +--- .../internal/model/IterableMappingMethod.ftl | 59 +++++++++++------ .../IterableElementConditionMapper.java | 9 ++- .../IterableElementConditionTest.java | 66 +++++++++++++++---- 4 files changed, 103 insertions(+), 42 deletions(-) diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/IterableMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/internal/model/IterableMappingMethod.java index dd375b5025..d638082ca6 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/IterableMappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/IterableMappingMethod.java @@ -83,11 +83,7 @@ protected IterableMappingMethod instantiateMappingMethod(Method method, Collecti } public boolean hasIterableConditionMethod() { - return getIterableConditionMethod() != null; - } - - public Method getIterableConditionMethod() { - return iterableConditionMethod; + return iterableConditionMethod != null; } public MethodReference getIterableConditionMethodReference() { @@ -101,10 +97,7 @@ public MethodReference getIterableConditionMethodReference() { ) ); - return MethodReference.forForgedMethod( - iterableConditionMethod, - parameterBindings - ); + return MethodReference.forForgedMethod( iterableConditionMethod, parameterBindings ); } private IterableMappingMethod(Method method, List annotations, 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 adc4005d8b..3c03881a65 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 @@ -11,7 +11,7 @@ <#if overridden>@Override <#lt>${accessibility.keyword} <@includeModel object=returnType/> ${name}(<#list parameters as param><@includeModel object=param/><#if param_has_next>, )<@throws/> { - <#list beforeMappingReferencesWithoutMappingTarget as callback> +<#list beforeMappingReferencesWithoutMappingTarget as callback> <@includeModel object=callback targetBeanName=resultName targetType=resultType/> <#if !callback_has_next> @@ -41,19 +41,19 @@ } - <#if resultType.arrayType> - <#if !existingInstanceMapping> - <#assign elementTypeString><@includeModel object=resultElementType/> - ${elementTypeString}[] ${resultName} = new ${elementTypeString?keep_before('[]')}[<@iterableSize/>]${elementTypeString?replace('[^\\[\\]]+', '', 'r')}; - - <#else> +<#-- <#if resultType.arrayType>--> +<#-- <#if !existingInstanceMapping>--> +<#-- <#assign elementTypeString><@includeModel object=resultElementType/>--> +<#-- ${elementTypeString}[] ${resultName} = new ${elementTypeString?keep_before('[]')}[<@iterableSize/>]${elementTypeString?replace('[^\\[\\]]+', '', 'r')};--> +<#-- --> +<#-- <#else>--> <#if existingInstanceMapping> ${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} = <@includeModel object=iterableCreation useSizeIfPossible=true/>; - +<#-- --> <#list beforeMappingReferencesWithMappingTarget as callback> <@includeModel object=callback targetBeanName=resultName targetType=resultType/> <#if !callback_has_next> @@ -61,17 +61,32 @@ <#if resultType.arrayType> - int ${index1Name} = 0; - for ( <@includeModel object=sourceElementType/> ${loopVariableName} : ${sourceParameter.name} ) { - <#if existingInstanceMapping> - if ( ( ${index1Name} >= ${resultName}.length ) || ( ${index1Name} >= <@iterableSize/> ) ) { - break; - } - - <@includeModel object=elementAssignment targetWriteAccessorName=resultName+"[${index1Name}]" targetType=resultElementType isTargetDefined=true/> - ${index1Name}++; - } - <#else> + + + <#if true> +<#-- <#if resultType.arrayType>--> +<#-- int ${index1Name} = 0;--> +<#-- for ( <@includeModel object=sourceElementType/> ${loopVariableName} : ${sourceParameter.name} ) {--> +<#-- <#if existingInstanceMapping>--> +<#-- if ( ( ${index1Name} >= ${resultName}.length ) || ( ${index1Name} >= <@iterableSize/> ) ) {--> +<#-- break;--> +<#-- }--> +<#-- --> +<#-- <#if hasIterableConditionMethod()>--> +<#-- if ( <@includeModel object=iterableConditionMethodReference /> ) {--> +<#-- <@includeModel object=elementAssignment targetWriteAccessorName=resultName+"[${index1Name}]" targetType=resultElementType isTargetDefined=true/>--> +<#-- ${index1Name}++;--> +<#-- }--> +<#-- <#else>--> +<#-- <@includeModel object=elementAssignment targetWriteAccessorName=resultName+"[${index1Name}]" targetType=resultElementType isTargetDefined=true/>--> +<#-- ${index1Name}++;--> +<#-- --> +<#-- }--> +<#-- Employee[] employeeTmp = employees.stream()--> +<#-- .filter(this::countryIsNotNull)--> +<#-- .map(this::map)--> +<#-- .toArray(Employee[]::new);--> +<#-- <#else>--> for ( <@includeModel object=sourceElementType/> ${loopVariableName} : ${sourceParameter.name} ) { <#if hasIterableConditionMethod()> if ( <@includeModel object=iterableConditionMethodReference /> ) { @@ -90,7 +105,11 @@ <#if returnType.name != "void"> - return ${resultName}; + <#if hasIterableConditionMethod() && resultType.arrayType> + ${resultName}.toArray( new <@includeModel object=resultElementType/>[0] ); + <#else> + return ${resultName}; + } <#macro throws> diff --git a/processor/src/test/java/org/mapstruct/ap/test/conditional/iterable/IterableElementConditionMapper.java b/processor/src/test/java/org/mapstruct/ap/test/conditional/iterable/IterableElementConditionMapper.java index 5e564a1d88..e27fa022f3 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/conditional/iterable/IterableElementConditionMapper.java +++ b/processor/src/test/java/org/mapstruct/ap/test/conditional/iterable/IterableElementConditionMapper.java @@ -27,7 +27,14 @@ public interface IterableElementConditionMapper { @Mapping(target = "ssid", source = "uniqueIdNumber") Employee map(EmployeeDto employee); - List map(List employees); + List mapListToList(List employees); + + List mapArrayToList(EmployeeDto[] employees); + +// Employee[] mapListToArray(List employees); +// +// Employee[] mapArrayToArray(EmployeeDto[] employees); + @IterableElementCondition default boolean countryIsNotNull(EmployeeDto value) { diff --git a/processor/src/test/java/org/mapstruct/ap/test/conditional/iterable/IterableElementConditionTest.java b/processor/src/test/java/org/mapstruct/ap/test/conditional/iterable/IterableElementConditionTest.java index 1fcb81e04f..3cd7fb0020 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/conditional/iterable/IterableElementConditionTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/conditional/iterable/IterableElementConditionTest.java @@ -6,7 +6,9 @@ package org.mapstruct.ap.test.conditional.iterable; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; import org.mapstruct.ap.test.conditional.Employee; import org.mapstruct.ap.test.conditional.EmployeeDto; @@ -22,16 +24,58 @@ @IssueKey("1610") @WithClasses({ Employee.class, - EmployeeDto.class + EmployeeDto.class, + IterableElementConditionMapper.class, }) public class IterableElementConditionTest { @ProcessorTest - @WithClasses({ - IterableElementConditionMapper.class - }) - public void conditionalMethodWithSourceParameter() { - IterableElementConditionMapper mapper = IterableElementConditionMapper.INSTANCE; + public void conditionalMethodListToList() { + + List result = IterableElementConditionMapper.INSTANCE.mapListToList( setupList() ); + + assertThatOnlyFilteredValuesMapped( result ); + } + + @ProcessorTest + public void conditionalMethodArrayToList() { + + List result = IterableElementConditionMapper.INSTANCE.mapArrayToList( setupArray() ); + + assertThatOnlyFilteredValuesMapped( result ); + } + +// @ProcessorTest +// public void conditionalMethodListToArray() { +// +// Employee[] result = IterableElementConditionMapper.INSTANCE.mapListToArray( setupList() ); +// +// assertThatOnlyFilteredValuesMapped( result ); +// } +// +// @ProcessorTest +// public void conditionalMethodArrayToArray() { +// +// Employee[] result = IterableElementConditionMapper.INSTANCE.mapArrayToArray( setupArray() ); +// +// assertThatOnlyFilteredValuesMapped( result ); +// } + + private static void assertThatOnlyFilteredValuesMapped(List result) { + assertThat( result ) + .singleElement() + .satisfies( + d -> assertThat( d.getName() ).isEqualTo( "Tester" ) + ); + } + + private static void assertThatOnlyFilteredValuesMapped(Employee[] result) { + assertThatOnlyFilteredValuesMapped( + Arrays.stream( result ).collect( Collectors.toList() ) + ); + } + + private static ArrayList setupList() { EmployeeDto dtoWithoutCountry = new EmployeeDto(); dtoWithoutCountry.setName( "Tester" ); @@ -47,13 +91,11 @@ public void conditionalMethodWithSourceParameter() { employees.add( dtoWithoutCountry ); employees.add( dtoWithCountry ); - List result = mapper.map( employees ); - assertThat( result ) - .singleElement() - .satisfies( - d -> assertThat(d.getName()).isEqualTo( "Tester" ) - ); + return employees; + } + private static EmployeeDto[] setupArray() { + return setupList().toArray( new EmployeeDto[0] ); } }