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] 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 10e64b700..dd375b502 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 java.util.Set; 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 @@ import org.mapstruct.ap.internal.model.source.SelectionParameters; */ 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 @@ public class IterableMappingMethod extends ContainerMappingMethod { 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 @@ public class IterableMappingMethod extends ContainerMappingMethod { 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 5fc1b0782..debaea36f 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.type.TypeMirror; 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 @@ public class MapperCreationProcessor implements ModelElementProcessor 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 ead8b4c24..adc4005d8 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>