From db3bb5eba0f95d352cb1ad06ec18e2f40dea6ed3 Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Thu, 13 Jul 2017 18:52:57 +0200 Subject: [PATCH] #1247 Make sure that nested target mappings works correctly for multiple source parameters --- .../NestedTargetPropertyMappingHolder.java | 142 ++++++++++++++++-- .../internal/model/source/MappingOptions.java | 16 +- .../mapstruct/ap/test/bugs/_1247/DtoIn.java | 41 +++++ .../mapstruct/ap/test/bugs/_1247/DtoOut.java | 44 ++++++ .../ap/test/bugs/_1247/InternalData.java | 37 +++++ .../ap/test/bugs/_1247/InternalDto.java | 44 ++++++ .../ap/test/bugs/_1247/Issue1247Mapper.java | 51 +++++++ .../ap/test/bugs/_1247/Issue1247Test.java | 101 +++++++++++++ .../ap/test/bugs/_1247/OtherDtoOut.java | 53 +++++++ .../ap/test/bugs/_1247/OtherInternalData.java | 46 ++++++ .../ap/test/bugs/_1247/OtherInternalDto.java | 53 +++++++ 11 files changed, 613 insertions(+), 15 deletions(-) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/DtoIn.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/DtoOut.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/InternalData.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/InternalDto.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/Issue1247Mapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/Issue1247Test.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/OtherDtoOut.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/OtherInternalData.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/OtherInternalDto.java diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/NestedTargetPropertyMappingHolder.java b/processor/src/main/java/org/mapstruct/ap/internal/model/NestedTargetPropertyMappingHolder.java index e6bb66274..730b91c1e 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/NestedTargetPropertyMappingHolder.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/NestedTargetPropertyMappingHolder.java @@ -19,8 +19,9 @@ package org.mapstruct.ap.internal.model; import java.util.ArrayList; -import java.util.LinkedHashMap; +import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -56,7 +57,8 @@ public class NestedTargetPropertyMappingHolder { Extractor() { @Override public PropertyEntry apply(SourceReference sourceReference) { - return first( sourceReference.getPropertyEntries() ); + return sourceReference.getPropertyEntries().isEmpty() ? null : + first( sourceReference.getPropertyEntries() ); } }; @@ -117,6 +119,8 @@ public class NestedTargetPropertyMappingHolder { private Method method; private MappingBuilderContext mappingContext; private Set existingVariableNames; + private List propertyMappings; + private Set handledTargets; public Builder method(Method method) { this.method = method; @@ -135,8 +139,8 @@ public class NestedTargetPropertyMappingHolder { public NestedTargetPropertyMappingHolder build() { List processedSourceParameters = new ArrayList(); - Set handledTargets = new HashSet(); - List propertyMappings = new ArrayList(); + handledTargets = new HashSet(); + propertyMappings = new ArrayList(); // first we group by the first property in the target properties and for each of those // properties we get the new mappings as if the first property did not exist. @@ -164,7 +168,7 @@ public class NestedTargetPropertyMappingHolder { // Lastly we need to group by the source references. This will allow us to actually create // the next mappings by popping source elements GroupedSourceReferences groupedSourceReferences = groupByPoppedSourceReferences( - entryByParam.getValue(), + entryByParam, groupedByTP.singleTargetReferences.get( targetProperty ) ); @@ -229,6 +233,13 @@ public class NestedTargetPropertyMappingHolder { handledTargets.add( entryByTP.getKey().getName() ); } + handleSourceParameterMappings( + groupedSourceReferences.sourceParameterMappings, + targetProperty, + sourceParameter, + forceUpdateMethod + ); + unprocessedDefinedTarget.put( targetProperty, groupedSourceReferences.notProcessedAppliesToAll ); } } @@ -242,6 +253,43 @@ public class NestedTargetPropertyMappingHolder { ); } + /** + * Handle the {@link PropertyMapping} creation for source parameter mappings. + * + * @param sourceParameterMappings the source parameter mappings for which property mapping should be done + * @param targetProperty the target property that is being mapped + * @param sourceParameter the source parameter that is used + * @param forceUpdateMethod whether we need to force an update method + */ + private void handleSourceParameterMappings(List sourceParameterMappings, PropertyEntry targetProperty, + Parameter sourceParameter, boolean forceUpdateMethod) { + if ( !sourceParameterMappings.isEmpty() ) { + // The source parameter mappings have no mappings, the source name is actually the parameter itself + MappingOptions nonNestedOptions = MappingOptions.forMappingsOnly( + new HashMap>(), + false, + true + ); + SourceReference reference = new SourceReference.BuilderFromProperty() + .sourceParameter( sourceParameter ) + .name( targetProperty.getName() ) + .build(); + + PropertyMapping propertyMapping = createPropertyMappingForNestedTarget( + nonNestedOptions, + targetProperty, + reference, + forceUpdateMethod + ); + + if ( propertyMapping != null ) { + propertyMappings.add( propertyMapping ); + } + + handledTargets.add( targetProperty.getName() ); + } + } + /** * The target references are popped. The {@code List<}{@link Mapping}{@code >} are keyed on the unique first * entries of the target references. @@ -464,15 +512,18 @@ public class NestedTargetPropertyMappingHolder { * * * - * @param mappings the list of {@link Mapping} that needs to be used for grouping on popped source references + * @param entryByParam the entry of a {@link Parameter} and it's associated {@link Mapping}(s) that need to + * be used for grouping on popped source references * @param singleTargetReferences the single target references that match the source mappings * * @return the Grouped Source References */ - private GroupedSourceReferences groupByPoppedSourceReferences(List mappings, + private GroupedSourceReferences groupByPoppedSourceReferences(Map.Entry> entryByParam, List singleTargetReferences) { + List mappings = entryByParam.getValue(); List nonNested = new ArrayList(); List appliesToAll = new ArrayList(); + List sourceParameterMappings = new ArrayList(); // group all mappings based on the top level name before popping Map> mappingsKeyedByProperty = new LinkedHashMap>(); @@ -496,7 +547,24 @@ public class NestedTargetPropertyMappingHolder { } } - populateWithSingleTargetReferences( mappingsKeyedByProperty, singleTargetReferences, PROPERTY_EXTRACTOR ); + // We consider that there were no mappings if there are no mappingsKeyedByProperty + // and no nonNested. appliesToAll Mappings are mappings that have no source reference and need to be + // applied to everything. + boolean hasNoMappings = mappingsKeyedByProperty.isEmpty() && nonNested.isEmpty(); + Parameter sourceParameter = entryByParam.getKey(); + List singleTargetReferencesToUse = + extractSingleTargetReferencesToUseAndPopulateSourceParameterMappings( + singleTargetReferences, + sourceParameterMappings, + hasNoMappings, + sourceParameter + ); + + populateWithSingleTargetReferences( + mappingsKeyedByProperty, + singleTargetReferencesToUse, + PROPERTY_EXTRACTOR + ); for ( Map.Entry> entry : mappingsKeyedByProperty.entrySet() ) { entry.getValue().addAll( appliesToAll ); @@ -516,10 +584,55 @@ public class NestedTargetPropertyMappingHolder { return new GroupedSourceReferences( mappingsKeyedByProperty, nonNested, - notProcessedAppliesToAll + notProcessedAppliesToAll, + sourceParameterMappings ); } + /** + * Extracts all relevant single target references and populates the {@code sourceParameterMappings} if needed. + * A relevant single target reference mapping is a mapping that has a valid source reference and is for + * the {@code sourceParameter}. If there are no mappings i.e. {@code hasNoMappings = true} and the source + * reference in the mapping has no property entries then add that to the {@code sourceParameterMappings} + * (mappings like this have found themselves here because there is a mapping method with multiple parameters + * and that are using the same sub-path in the target properties). + * + * @param singleTargetReferences All the single target references for a target property + * @param sourceParameterMappings a List that needs to be populated with valid mappings when {@code + * hasNoMappings = true} and there are no property entries in the source reference + * @param hasNoMappings parameter indicating whether there were any extracted mappings for this target property + * @param sourceParameter the source parameter for which the grouping is being done + * + * @return a list with valid single target references + */ + private List extractSingleTargetReferencesToUseAndPopulateSourceParameterMappings( + List singleTargetReferences, List sourceParameterMappings, boolean hasNoMappings, + Parameter sourceParameter) { + List singleTargetReferencesToUse = null; + if ( singleTargetReferences != null ) { + singleTargetReferencesToUse = new ArrayList( singleTargetReferences.size() ); + for ( Mapping mapping : singleTargetReferences ) { + if ( mapping.getSourceReference() == null || !mapping.getSourceReference().isValid() || + !sourceParameter.equals( mapping.getSourceReference().getParameter() ) ) { + // If the mapping has no sourceReference, it is not valid or it does not have the same source + // parameter then we need to ignore it. When a mapping method has multiple parameters it can + // happen that different parameters somehow have same path in the nesting + continue; + } + if ( hasNoMappings && mapping.getSourceReference().getPropertyEntries().isEmpty() ) { + // If there were no mappings for this source parameter and there are no property entries + // that means that this could be for a mapping method with multiple parameters. + // We have to consider and map this separately + sourceParameterMappings.add( mapping ); + } + else { + singleTargetReferencesToUse.add( mapping ); + } + } + } + return singleTargetReferencesToUse; + } + private Map> groupByTargetName(List mappingList) { Map> result = new LinkedHashMap>(); for ( Mapping mapping : mappingList ) { @@ -563,11 +676,9 @@ public class NestedTargetPropertyMappingHolder { //This are non nested target references only their property needs to be added as they most probably // define it for ( Mapping mapping : singleTargetReferences ) { - if ( mapping.getSourceReference() != null && mapping.getSourceReference().isValid() - && !mapping.getSourceReference().getPropertyEntries().isEmpty() ) { - //TODO is this OK? Why there are no propertyEntries? For the Inverse LetterMapper for example + if ( mapping.getSourceReference() != null && mapping.getSourceReference().isValid() ) { K key = keyExtractor.apply( mapping.getSourceReference() ); - if ( !map.containsKey( key ) ) { + if ( key != null && !map.containsKey( key ) ) { map.put( key, new ArrayList() ); } } @@ -642,12 +753,15 @@ public class NestedTargetPropertyMappingHolder { private final Map> groupedBySourceReferences; private final List nonNested; private final List notProcessedAppliesToAll; + private final List sourceParameterMappings; private GroupedSourceReferences(Map> groupedBySourceReferences, - List nonNested, List notProcessedAppliesToAll) { + List nonNested, List notProcessedAppliesToAll, + List sourceParameterMappings) { this.groupedBySourceReferences = groupedBySourceReferences; this.nonNested = nonNested; this.notProcessedAppliesToAll = notProcessedAppliesToAll; + this.sourceParameterMappings = sourceParameterMappings; } } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/MappingOptions.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/MappingOptions.java index aa2d0cbea..c09ff785a 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/MappingOptions.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/MappingOptions.java @@ -81,11 +81,25 @@ public class MappingOptions { */ public static MappingOptions forMappingsOnly(Map> mappings, boolean restrictToDefinedMappings) { + return forMappingsOnly( mappings, restrictToDefinedMappings, restrictToDefinedMappings ); + + } + + /** + * creates mapping options with only regular mappings + * + * @param mappings regular mappings to add + * @param restrictToDefinedMappings whether to restrict the mappings only to the defined mappings + * @param forForgedMethods whether the mappings are for forged methods + * @return MappingOptions with only regular mappings + */ + public static MappingOptions forMappingsOnly(Map> mappings, + boolean restrictToDefinedMappings, boolean forForgedMethods) { return new MappingOptions( mappings, null, null, - restrictToDefinedMappings ? BeanMapping.forForgedMethods() : null, + forForgedMethods ? BeanMapping.forForgedMethods() : null, Collections.emptyList(), restrictToDefinedMappings ); diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/DtoIn.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/DtoIn.java new file mode 100644 index 000000000..5012d60b8 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/DtoIn.java @@ -0,0 +1,41 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.bugs._1247; + +/** + * @author Filip Hrisafov + */ +public class DtoIn { + + private final String data; + private final String data2; + + public DtoIn(String data, String data2) { + this.data = data; + this.data2 = data2; + } + + public String getData() { + return data; + } + + public String getData2() { + return data2; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/DtoOut.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/DtoOut.java new file mode 100644 index 000000000..1a5cefc57 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/DtoOut.java @@ -0,0 +1,44 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.bugs._1247; + +/** + * @author Filip Hrisafov + */ +public class DtoOut { + + private String data; + private InternalDto internal; + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public InternalDto getInternal() { + return internal; + } + + public void setInternal(InternalDto internal) { + this.internal = internal; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/InternalData.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/InternalData.java new file mode 100644 index 000000000..aafdc6838 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/InternalData.java @@ -0,0 +1,37 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.bugs._1247; + +import java.util.List; + +/** + * @author Filip Hrisafov + */ +public class InternalData { + + private List list; + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/InternalDto.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/InternalDto.java new file mode 100644 index 000000000..6e3ec8a5a --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/InternalDto.java @@ -0,0 +1,44 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.bugs._1247; + +/** + * @author Filip Hrisafov + */ +public class InternalDto { + + private String data2; + private InternalData internalData; + + public String getData2() { + return data2; + } + + public void setData2(String data2) { + this.data2 = data2; + } + + public InternalData getInternalData() { + return internalData; + } + + public void setInternalData(InternalData internalData) { + this.internalData = internalData; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/Issue1247Mapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/Issue1247Mapper.java new file mode 100644 index 000000000..ba3086631 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/Issue1247Mapper.java @@ -0,0 +1,51 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.bugs._1247; + +import java.util.List; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +/** + * @author Filip Hrisafov + */ +@Mapper +public interface Issue1247Mapper { + + Issue1247Mapper INSTANCE = Mappers.getMapper( Issue1247Mapper.class ); + + @Mappings( { + @Mapping(target = "internal", source = "in"), + @Mapping(target = "internal.internalData.list", source = "list") + } ) + DtoOut map(DtoIn in, List list); + + @Mappings( { + @Mapping(target = "internal", source = "in"), + @Mapping(target = "internal.expression", expression = "java(\"testingExpression\")"), + @Mapping(target = "internal.internalData.list", source = "list"), + @Mapping(target = "internal.internalData.defaultValue", source = "in.data2", defaultValue = "missing"), + @Mapping(target = "constant", constant = "someConstant") + } ) + OtherDtoOut mapWithConstantExpressionAndDefault(DtoIn in, List list); + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/Issue1247Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/Issue1247Test.java new file mode 100644 index 000000000..beaef236c --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/Issue1247Test.java @@ -0,0 +1,101 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.bugs._1247; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mapstruct.ap.testutil.IssueKey; +import org.mapstruct.ap.testutil.WithClasses; +import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Filip Hrisafov + */ +@IssueKey("1247") +@RunWith(AnnotationProcessorTestRunner.class) +@WithClasses({ + Issue1247Mapper.class, + DtoIn.class, + DtoOut.class, + InternalData.class, + InternalDto.class, + OtherDtoOut.class, + OtherInternalData.class, + OtherInternalDto.class +}) +public class Issue1247Test { + + @Test + public void shouldCorrectlyUseMappings() { + + DtoIn in = new DtoIn( "data", "data2" ); + List list = Arrays.asList( "first", "second" ); + DtoOut out = Issue1247Mapper.INSTANCE.map( in, list ); + + assertThat( out ).isNotNull(); + assertThat( out.getData() ).isEqualTo( "data" ); + assertThat( out.getInternal() ).isNotNull(); + assertThat( out.getInternal().getData2() ).isEqualTo( "data2" ); + assertThat( out.getInternal().getInternalData() ).isNotNull(); + assertThat( out.getInternal().getInternalData().getList() ).containsExactly( "first", "second" ); + } + + @Test + public void shouldCorrectlyUseMappingsWithConstantsExpressionsAndDefaults() { + + DtoIn in = new DtoIn( "data", "data2" ); + List list = Arrays.asList( "first", "second" ); + OtherDtoOut out = Issue1247Mapper.INSTANCE.mapWithConstantExpressionAndDefault( in, list ); + + assertThat( out ).isNotNull(); + assertThat( out.getData() ).isEqualTo( "data" ); + assertThat( out.getConstant() ).isEqualTo( "someConstant" ); + assertThat( out.getInternal() ).isNotNull(); + // This will not be mapped by the @Mapping(target = "internal", source = "in") because we have one more + // symmetric mapping @Mapping(target = "internal.expression", expression = "java(\"testingExpression\")") + assertThat( out.getInternal().getData2() ).isNull(); + assertThat( out.getInternal().getExpression() ).isEqualTo( "testingExpression" ); + assertThat( out.getInternal().getInternalData() ).isNotNull(); + assertThat( out.getInternal().getInternalData().getList() ).containsExactly( "first", "second" ); + assertThat( out.getInternal().getInternalData().getDefaultValue() ).isEqualTo( "data2" ); + } + + @Test + public void shouldCorrectlyUseMappingsWithConstantsExpressionsAndUseDefault() { + + DtoIn in = new DtoIn( "data", null ); + List list = Arrays.asList( "first", "second" ); + OtherDtoOut out = Issue1247Mapper.INSTANCE.mapWithConstantExpressionAndDefault( in, list ); + + assertThat( out ).isNotNull(); + assertThat( out.getData() ).isEqualTo( "data" ); + assertThat( out.getConstant() ).isEqualTo( "someConstant" ); + assertThat( out.getInternal() ).isNotNull(); + assertThat( out.getInternal().getData2() ).isNull(); + assertThat( out.getInternal().getExpression() ).isEqualTo( "testingExpression" ); + assertThat( out.getInternal().getInternalData() ).isNotNull(); + assertThat( out.getInternal().getInternalData().getList() ).containsExactly( "first", "second" ); + assertThat( out.getInternal().getInternalData().getDefaultValue() ).isEqualTo( "missing" ); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/OtherDtoOut.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/OtherDtoOut.java new file mode 100644 index 000000000..36439f0ce --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/OtherDtoOut.java @@ -0,0 +1,53 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.bugs._1247; + +/** + * @author Filip Hrisafov + */ +public class OtherDtoOut { + + private String data; + private OtherInternalDto internal; + private String constant; + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public OtherInternalDto getInternal() { + return internal; + } + + public void setInternal(OtherInternalDto internal) { + this.internal = internal; + } + + public String getConstant() { + return constant; + } + + public void setConstant(String constant) { + this.constant = constant; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/OtherInternalData.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/OtherInternalData.java new file mode 100644 index 000000000..f06bacde4 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/OtherInternalData.java @@ -0,0 +1,46 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.bugs._1247; + +import java.util.List; + +/** + * @author Filip Hrisafov + */ +public class OtherInternalData { + + private List list; + private String defaultValue; + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public String getDefaultValue() { + return defaultValue; + } + + public void setDefaultValue(String defaultValue) { + this.defaultValue = defaultValue; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/OtherInternalDto.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/OtherInternalDto.java new file mode 100644 index 000000000..91fe5d7ea --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1247/OtherInternalDto.java @@ -0,0 +1,53 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.bugs._1247; + +/** + * @author Filip Hrisafov + */ +public class OtherInternalDto { + + private String data2; + private String expression; + private OtherInternalData internalData; + + public String getData2() { + return data2; + } + + public void setData2(String data2) { + this.data2 = data2; + } + + public String getExpression() { + return expression; + } + + public void setExpression(String expression) { + this.expression = expression; + } + + public OtherInternalData getInternalData() { + return internalData; + } + + public void setInternalData(OtherInternalData internalData) { + this.internalData = internalData; + } +}