From a5a82cf5f1798e512a3b6d982f203c34b022a3d0 Mon Sep 17 00:00:00 2001 From: sjaakd Date: Sun, 28 Aug 2016 22:43:29 +0200 Subject: [PATCH] #700 Fixing enum constants and adding unit test. --- .../ap/internal/model/PropertyMapping.java | 49 ++++++++++++++---- .../model/assignment/EnumConstantWrapper.java | 50 +++++++++++++++++++ .../mapstruct/ap/internal/util/Message.java | 1 + .../model/assignment/EnumConstantWrapper.ftl | 21 ++++++++ .../ap/test/source/constants/CountryEnum.java | 28 +++++++++++ .../source/constants/ErroneousMapper1.java | 3 +- .../source/constants/ErroneousMapper2.java | 3 +- .../source/constants/ErroneousMapper3.java | 3 +- .../source/constants/ErroneousMapper4.java | 3 +- .../source/constants/ErroneousMapper5.java | 46 +++++++++++++++++ .../source/constants/SourceConstantsTest.java | 45 ++++++++++++++--- .../source/constants/SourceTargetMapper.java | 3 +- .../ap/test/source/constants/Target.java | 9 ++++ 13 files changed, 242 insertions(+), 22 deletions(-) create mode 100644 processor/src/main/java/org/mapstruct/ap/internal/model/assignment/EnumConstantWrapper.java create mode 100644 processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/EnumConstantWrapper.ftl create mode 100644 processor/src/test/java/org/mapstruct/ap/test/source/constants/CountryEnum.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/source/constants/ErroneousMapper5.java diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java b/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java index 1f2446045..e4f6410c5 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java @@ -35,6 +35,7 @@ import javax.lang.model.type.DeclaredType; import org.mapstruct.ap.internal.model.assignment.AdderWrapper; import org.mapstruct.ap.internal.model.assignment.ArrayCopyWrapper; import org.mapstruct.ap.internal.model.assignment.Assignment; +import org.mapstruct.ap.internal.model.assignment.EnumConstantWrapper; import org.mapstruct.ap.internal.model.assignment.EnumSetCopyWrapper; import org.mapstruct.ap.internal.model.assignment.GetterWrapperForCollectionsAndMaps; import org.mapstruct.ap.internal.model.assignment.NewCollectionOrMapWrapper; @@ -686,17 +687,23 @@ public class PropertyMapping extends ModelElement { String mappedElement = "constant '" + constantExpression + "'"; Type sourceType = ctx.getTypeFactory().getType( String.class ); - Assignment assignment = ctx.getMappingResolver().getTargetAssignment( - method, - mappedElement, - sourceType, - targetType, - targetPropertyName, - formattingParameters, - selectionParameters, - constantExpression, - method.getMappingTargetParameter() != null - ); + Assignment assignment = null; + if ( !targetType.isEnumType() ) { + assignment = ctx.getMappingResolver().getTargetAssignment( + method, + mappedElement, + sourceType, + targetType, + targetPropertyName, + formattingParameters, + selectionParameters, + constantExpression, + method.getMappingTargetParameter() != null + ); + } + else { + assignment = getEnumAssignment(); + } if ( assignment != null ) { @@ -751,6 +758,26 @@ public class PropertyMapping extends ModelElement { null ); } + + private Assignment getEnumAssignment() { + Assignment assignment = null; + // String String quotation marks. + String enumExpression = constantExpression.substring( 1, constantExpression.length() - 1 ); + if ( targetType.getEnumConstants().contains( enumExpression ) ) { + assignment = AssignmentFactory.createDirect( enumExpression ); + assignment = new EnumConstantWrapper( assignment, targetType ); + } + else { + ctx.getMessager().printMessage( method.getExecutable(), + Message.CONSTANTMAPPING_NON_EXISTING_CONSTANT, + constantExpression, + targetType, + targetPropertyName + ); + } + return assignment; + } + } public static class JavaExpressionMappingBuilder extends MappingBuilderBase { diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/EnumConstantWrapper.java b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/EnumConstantWrapper.java new file mode 100644 index 000000000..57731c659 --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/EnumConstantWrapper.java @@ -0,0 +1,50 @@ +/** + * Copyright 2012-2016 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.internal.model.assignment; + +import java.util.HashSet; +import java.util.Set; +import org.mapstruct.ap.internal.model.common.Type; + +/** + * + * @author Sjaak Derksen + */ +public class EnumConstantWrapper extends AssignmentWrapper { + + private final Type enumType; + + public EnumConstantWrapper(Assignment decoratedAssignment, Type enumType ) { + super( decoratedAssignment ); + this.enumType = enumType; + } + + @Override + public Set getImportTypes() { + Set imported = new HashSet( getAssignment().getImportTypes() ); + imported.add( enumType ); + return imported; + } + + @Override + public String toString() { + return enumType.getName() + "." + getAssignment(); + } + +} diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/Message.java b/processor/src/main/java/org/mapstruct/ap/internal/util/Message.java index 7809dcf00..bace188b0 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/util/Message.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/util/Message.java @@ -56,6 +56,7 @@ public enum Message { CONSTANTMAPPING_MAPPING_NOT_FOUND( "Can't map \"%s %s\" to \"%s %s\"." ), CONSTANTMAPPING_NO_READ_ACCESSOR_FOR_TARGET_TYPE( "No read accessor found for property \"%s\" in target type." ), + CONSTANTMAPPING_NON_EXISTING_CONSTANT( "Constant %s doesn't exist in enum type %s for property \"%s\"." ), MAPMAPPING_KEY_MAPPING_NOT_FOUND( "No implementation can be generated for this method. Found no method nor implicit conversion for mapping source key type to target key type." ), MAPMAPPING_VALUE_MAPPING_NOT_FOUND( "No implementation can be generated for this method. Found no method nor implicit conversion for mapping source value type to target value type." ), diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/EnumConstantWrapper.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/EnumConstantWrapper.ftl new file mode 100644 index 000000000..377ccfede --- /dev/null +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/EnumConstantWrapper.ftl @@ -0,0 +1,21 @@ +<#-- + + Copyright 2012-2016 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. + +--> +${ext.targetType.name}.${assignment} \ No newline at end of file diff --git a/processor/src/test/java/org/mapstruct/ap/test/source/constants/CountryEnum.java b/processor/src/test/java/org/mapstruct/ap/test/source/constants/CountryEnum.java new file mode 100644 index 000000000..42040c206 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/source/constants/CountryEnum.java @@ -0,0 +1,28 @@ +/** + * Copyright 2012-2016 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.source.constants; + +/** + * + * @author Sjaak Derksen + */ +public enum CountryEnum { + + GERMANY, THE_NETHERLANDS, BELGIUM; +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/source/constants/ErroneousMapper1.java b/processor/src/test/java/org/mapstruct/ap/test/source/constants/ErroneousMapper1.java index 97677c56c..841150b4f 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/source/constants/ErroneousMapper1.java +++ b/processor/src/test/java/org/mapstruct/ap/test/source/constants/ErroneousMapper1.java @@ -37,7 +37,8 @@ public interface ErroneousMapper1 { @Mapping(source = "test", target = "integerConstant", constant = "14"), @Mapping(target = "longWrapperConstant", constant = "3001"), @Mapping(target = "dateConstant", dateFormat = "dd-MM-yyyy", constant = "09-01-2014"), - @Mapping(target = "nameConstants", constant = "jack-jill-tom") + @Mapping(target = "nameConstants", constant = "jack-jill-tom"), + @Mapping(target = "country", constant = "THE_NETHERLANDS") }) Target sourceToTarget(Source s); } diff --git a/processor/src/test/java/org/mapstruct/ap/test/source/constants/ErroneousMapper2.java b/processor/src/test/java/org/mapstruct/ap/test/source/constants/ErroneousMapper2.java index 92155724e..00819e031 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/source/constants/ErroneousMapper2.java +++ b/processor/src/test/java/org/mapstruct/ap/test/source/constants/ErroneousMapper2.java @@ -36,7 +36,8 @@ public interface ErroneousMapper2 { @Mapping(target = "integerConstant"), @Mapping(target = "longWrapperConstant", constant = "3001"), @Mapping(target = "dateConstant", dateFormat = "dd-MM-yyyy", constant = "09-01-2014"), - @Mapping(target = "nameConstants", constant = "jack-jill-tom") + @Mapping(target = "nameConstants", constant = "jack-jill-tom"), + @Mapping(target = "country", constant = "THE_NETHERLANDS") }) Target sourceToTarget(Source s); } diff --git a/processor/src/test/java/org/mapstruct/ap/test/source/constants/ErroneousMapper3.java b/processor/src/test/java/org/mapstruct/ap/test/source/constants/ErroneousMapper3.java index 8d0b7cb52..a4a1cb28e 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/source/constants/ErroneousMapper3.java +++ b/processor/src/test/java/org/mapstruct/ap/test/source/constants/ErroneousMapper3.java @@ -37,7 +37,8 @@ public interface ErroneousMapper3 { @Mapping(target = "integerConstant", expression = "java('test')", constant = "14"), @Mapping(target = "longWrapperConstant", constant = "3001"), @Mapping(target = "dateConstant", dateFormat = "dd-MM-yyyy", constant = "09-01-2014"), - @Mapping(target = "nameConstants", constant = "jack-jill-tom") + @Mapping(target = "nameConstants", constant = "jack-jill-tom"), + @Mapping(target = "country", constant = "THE_NETHERLANDS") }) Target sourceToTarget(Source s); } diff --git a/processor/src/test/java/org/mapstruct/ap/test/source/constants/ErroneousMapper4.java b/processor/src/test/java/org/mapstruct/ap/test/source/constants/ErroneousMapper4.java index c966b4bf6..0e5eb3be9 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/source/constants/ErroneousMapper4.java +++ b/processor/src/test/java/org/mapstruct/ap/test/source/constants/ErroneousMapper4.java @@ -37,7 +37,8 @@ public interface ErroneousMapper4 { @Mapping(source = "test", target = "integerConstant", expression = "java('test')"), @Mapping(target = "longWrapperConstant", constant = "3001"), @Mapping(target = "dateConstant", dateFormat = "dd-MM-yyyy", constant = "09-01-2014"), - @Mapping(target = "nameConstants", constant = "jack-jill-tom") + @Mapping(target = "nameConstants", constant = "jack-jill-tom"), + @Mapping(target = "country", constant = "THE_NETHERLANDS") }) Target sourceToTarget(Source s); } diff --git a/processor/src/test/java/org/mapstruct/ap/test/source/constants/ErroneousMapper5.java b/processor/src/test/java/org/mapstruct/ap/test/source/constants/ErroneousMapper5.java new file mode 100644 index 000000000..49b91fde6 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/source/constants/ErroneousMapper5.java @@ -0,0 +1,46 @@ +/** + * Copyright 2012-2016 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.source.constants; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +/** + * @author Sjaak Derksen + */ +@Mapper(uses = StringListMapper.class) +public interface ErroneousMapper5 { + + ErroneousMapper5 INSTANCE = Mappers.getMapper( ErroneousMapper5.class ); + + @Mappings({ + @Mapping(target = "stringConstant", constant = "stringConstant"), + @Mapping(target = "emptyStringConstant", constant = ""), + @Mapping(target = "integerConstant", constant = "14"), + @Mapping(target = "longWrapperConstant", constant = "3001"), + @Mapping(target = "dateConstant", dateFormat = "dd-MM-yyyy", constant = "09-01-2014"), + @Mapping(target = "nameConstants", constant = "jack-jill-tom"), + @Mapping(target = "country", constant = "DENMARK") + }) + Target sourceToTarget(Source s); + + Source targetToSource(Target t); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/source/constants/SourceConstantsTest.java b/processor/src/test/java/org/mapstruct/ap/test/source/constants/SourceConstantsTest.java index ec6bc1b14..db87abfc2 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/source/constants/SourceConstantsTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/source/constants/SourceConstantsTest.java @@ -49,6 +49,7 @@ public class SourceConstantsTest { Source.class, Source2.class, Target.class, + CountryEnum.class, SourceTargetMapper.class, StringListMapper.class }) @@ -66,6 +67,7 @@ public class SourceConstantsTest { assertThat( target.getLongWrapperConstant() ).isEqualTo( new Long( 3001L ) ); assertThat( target.getDateConstant() ).isEqualTo( getDate( "dd-MM-yyyy", "09-01-2014" ) ); assertThat( target.getNameConstants() ).isEqualTo( Arrays.asList( "jack", "jill", "tom" ) ); + assertThat( target.getCountry() ).isEqualTo( CountryEnum.THE_NETHERLANDS ); } @Test @@ -73,6 +75,7 @@ public class SourceConstantsTest { @WithClasses({ Source.class, Target.class, + CountryEnum.class, SourceTargetMapper.class, StringListMapper.class }) @@ -91,6 +94,7 @@ public class SourceConstantsTest { @WithClasses({ Source.class, Target.class, + CountryEnum.class, ErroneousMapper1.class, StringListMapper.class }) @@ -99,12 +103,12 @@ public class SourceConstantsTest { diagnostics = { @Diagnostic(type = ErroneousMapper1.class, kind = Kind.ERROR, - line = 42, + line = 43, messageRegExp = "Source and constant are both defined in @Mapping, either define a source or a " + "constant"), @Diagnostic(type = ErroneousMapper1.class, kind = Kind.WARNING, - line = 42, + line = 43, messageRegExp = "Unmapped target property: \"integerConstant\"") } ) @@ -116,6 +120,7 @@ public class SourceConstantsTest { @WithClasses({ Source.class, Target.class, + CountryEnum.class, ErroneousMapper3.class, StringListMapper.class }) @@ -124,13 +129,13 @@ public class SourceConstantsTest { diagnostics = { @Diagnostic(type = ErroneousMapper3.class, kind = Kind.ERROR, - line = 42, + line = 43, messageRegExp = "Expression and constant are both defined in @Mapping, either define an expression or a " + "constant"), @Diagnostic(type = ErroneousMapper3.class, kind = Kind.WARNING, - line = 42, + line = 43, messageRegExp = "Unmapped target property: \"integerConstant\"") } ) @@ -142,6 +147,7 @@ public class SourceConstantsTest { @WithClasses({ Source.class, Target.class, + CountryEnum.class, ErroneousMapper4.class, StringListMapper.class }) @@ -150,12 +156,12 @@ public class SourceConstantsTest { diagnostics = { @Diagnostic(type = ErroneousMapper4.class, kind = Kind.ERROR, - line = 42, + line = 43, messageRegExp = "Source and expression are both defined in @Mapping, either define a source or an " + "expression"), @Diagnostic(type = ErroneousMapper4.class, kind = Kind.WARNING, - line = 42, + line = 43, messageRegExp = "Unmapped target property: \"integerConstant\"") } ) @@ -184,6 +190,33 @@ public class SourceConstantsTest { assertThat( target.getSomeConstant() ).isEqualTo( "stringConstant" ); } + @Test + @IssueKey("700") + @WithClasses({ + Source.class, + Target.class, + CountryEnum.class, + ErroneousMapper5.class, + StringListMapper.class + }) + @ExpectedCompilationOutcome( + value = CompilationResult.FAILED, + diagnostics = { + @Diagnostic(type = ErroneousMapper5.class, + kind = Kind.ERROR, + line = 43, + messageRegExp = "^Constant \"DENMARK\" doesn't exist in enum type org.mapstruct.ap.test.source." + + "constants.CountryEnum for property \"country\".$"), + @Diagnostic(type = ErroneousMapper5.class, + kind = Kind.ERROR, + line = 43, + messageRegExp = "^Can't map \"java.lang.String \"DENMARK\"\" to \"org.mapstruct.ap.test.source." + + "constants.CountryEnum country\".$") + } + ) + public void errorOnNonExistingEnumConstant() throws ParseException { + } + private Date getDate(String format, String date) throws ParseException { SimpleDateFormat dateFormat = new SimpleDateFormat( format ); Date result = dateFormat.parse( date ); diff --git a/processor/src/test/java/org/mapstruct/ap/test/source/constants/SourceTargetMapper.java b/processor/src/test/java/org/mapstruct/ap/test/source/constants/SourceTargetMapper.java index f76c46f0d..7e597f6f8 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/source/constants/SourceTargetMapper.java +++ b/processor/src/test/java/org/mapstruct/ap/test/source/constants/SourceTargetMapper.java @@ -37,7 +37,8 @@ public interface SourceTargetMapper { @Mapping(target = "integerConstant", constant = "14"), @Mapping(target = "longWrapperConstant", constant = "3001"), @Mapping(target = "dateConstant", dateFormat = "dd-MM-yyyy", constant = "09-01-2014"), - @Mapping(target = "nameConstants", constant = "jack-jill-tom") + @Mapping(target = "nameConstants", constant = "jack-jill-tom"), + @Mapping(target = "country", constant = "THE_NETHERLANDS") }) Target sourceToTarget(Source s); diff --git a/processor/src/test/java/org/mapstruct/ap/test/source/constants/Target.java b/processor/src/test/java/org/mapstruct/ap/test/source/constants/Target.java index cc24478fa..6b6b3c6a0 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/source/constants/Target.java +++ b/processor/src/test/java/org/mapstruct/ap/test/source/constants/Target.java @@ -34,6 +34,7 @@ public class Target { private Long longWrapperConstant; private Date dateConstant; private List nameConstants = new ArrayList(); + private CountryEnum country; public String getPropertyThatShouldBeMapped() { return propertyThatShouldBeMapped; @@ -87,4 +88,12 @@ public class Target { this.emptyStringConstant = emptyStringConstant; } + public CountryEnum getCountry() { + return country; + } + + public void setCountry(CountryEnum country) { + this.country = country; + } + }