From 060f17e3e2e6d8ec9cd029d9721af2fa25a4c393 Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Sun, 20 Sep 2020 12:48:47 +0200 Subject: [PATCH] #2125 Report an error when source parameter could not be determined from target mapping --- .../ap/internal/model/BeanMappingMethod.java | 27 +++++++ .../mapstruct/ap/internal/util/Message.java | 2 + .../bugs/_2077/Issue2077ErroneousMapper.java | 3 - .../ap/test/bugs/_2077/Issue2077Test.java | 5 +- .../mapstruct/ap/test/bugs/_2125/Comment.java | 27 +++++++ .../bugs/_2125/Issue2125ErroneousMapper.java | 28 ++++++++ .../ap/test/bugs/_2125/Issue2125Mapper.java | 28 ++++++++ .../ap/test/bugs/_2125/Issue2125Test.java | 71 +++++++++++++++++++ .../ap/test/bugs/_2125/Repository.java | 28 ++++++++ 9 files changed, 214 insertions(+), 5 deletions(-) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2125/Comment.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2125/Issue2125ErroneousMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2125/Issue2125Mapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2125/Issue2125Test.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2125/Repository.java diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java index c2434da51..deeadc7ea 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java @@ -65,6 +65,8 @@ import static org.mapstruct.ap.internal.util.Message.BEANMAPPING_NOT_ASSIGNABLE; import static org.mapstruct.ap.internal.util.Message.GENERAL_ABSTRACT_RETURN_TYPE; import static org.mapstruct.ap.internal.util.Message.GENERAL_AMBIGUOUS_CONSTRUCTORS; import static org.mapstruct.ap.internal.util.Message.GENERAL_CONSTRUCTOR_PROPERTIES_NOT_MATCHING_PARAMETERS; +import static org.mapstruct.ap.internal.util.Message.PROPERTYMAPPING_CANNOT_DETERMINE_SOURCE_PARAMETER_FROM_TARGET; +import static org.mapstruct.ap.internal.util.Message.PROPERTYMAPPING_CANNOT_DETERMINE_SOURCE_PROPERTY_FROM_TARGET; /** * A {@link MappingMethod} implemented by a {@link Mapper} class which maps one bean type to another, optionally @@ -1113,6 +1115,31 @@ public class BeanMappingMethod extends NormalTypeMappingMethod { errorOccured = true; } } + else { + errorOccured = true; + + if ( method.getSourceParameters().size() == 1 ) { + ctx.getMessager() + .printMessage( + method.getExecutable(), + mapping.getMirror(), + mapping.getTargetAnnotationValue(), + PROPERTYMAPPING_CANNOT_DETERMINE_SOURCE_PROPERTY_FROM_TARGET, + method.getSourceParameters().get( 0 ).getName(), + targetPropertyName + ); + } + else { + ctx.getMessager() + .printMessage( + method.getExecutable(), + mapping.getMirror(), + mapping.getTargetAnnotationValue(), + PROPERTYMAPPING_CANNOT_DETERMINE_SOURCE_PARAMETER_FROM_TARGET, + targetPropertyName + ); + } + } } // remaining are the mappings without a 'source' so, 'only' a date format or qualifiers if ( propertyMapping != null ) { 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 87d3a9abd..67aa5849b 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 @@ -73,6 +73,8 @@ public enum Message { PROPERTYMAPPING_NO_READ_ACCESSOR_FOR_TARGET_TYPE( "No read accessor found for property \"%s\" in target type." ), PROPERTYMAPPING_NO_WRITE_ACCESSOR_FOR_TARGET_TYPE( "No write accessor found for property \"%s\" in target type." ), PROPERTYMAPPING_WHITESPACE_TRIMMED( "The property named \"%s\" has whitespaces, using trimmed property \"%s\" instead.", Diagnostic.Kind.WARNING ), + PROPERTYMAPPING_CANNOT_DETERMINE_SOURCE_PROPERTY_FROM_TARGET("The type of parameter \"%s\" has no property named \"%s\". Please define the source property explicitly."), + PROPERTYMAPPING_CANNOT_DETERMINE_SOURCE_PARAMETER_FROM_TARGET("No property named \"%s\" exists in source parameter(s). Please define the source explicitly."), CONVERSION_LOSSY_WARNING( "%s has a possibly lossy conversion from %s to %s.", Diagnostic.Kind.WARNING ), CONVERSION_LOSSY_ERROR( "Can't map %s. It has a possibly lossy conversion from %s to %s." ), diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2077/Issue2077ErroneousMapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2077/Issue2077ErroneousMapper.java index ecbff6380..9d38e8bf4 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2077/Issue2077ErroneousMapper.java +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2077/Issue2077ErroneousMapper.java @@ -8,7 +8,6 @@ package org.mapstruct.ap.test.bugs._2077; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.ReportingPolicy; -import org.mapstruct.factory.Mappers; /** * @author Sjaak Derksen @@ -16,8 +15,6 @@ import org.mapstruct.factory.Mappers; @Mapper( unmappedTargetPolicy = ReportingPolicy.ERROR ) public interface Issue2077ErroneousMapper { - Issue2077ErroneousMapper INSTANCE = Mappers.getMapper( Issue2077ErroneousMapper.class ); - @Mapping(target = "s1", defaultValue = "xyz" ) Target map(String source); diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2077/Issue2077Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2077/Issue2077Test.java index d8c3a1e5d..332c3034d 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2077/Issue2077Test.java +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2077/Issue2077Test.java @@ -30,8 +30,9 @@ public class Issue2077Test { diagnostics = { @Diagnostic(type = Issue2077ErroneousMapper.class, kind = ERROR, - line = 22, - message = "Unmapped target property: \"s1\".") + line = 18, + message = "The type of parameter \"source\" has no property named \"s1\". Please define the source " + + "property explicitly.") } ) public void shouldNotCompile() { diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2125/Comment.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2125/Comment.java new file mode 100644 index 000000000..13fe680bb --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2125/Comment.java @@ -0,0 +1,27 @@ +/* + * 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.bugs._2125; + +/** + * @author Filip Hrisafov + */ +public class Comment { + private final Integer issueId; + private final String comment; + + public Comment(Integer issueId, String comment) { + this.issueId = issueId; + this.comment = comment; + } + + public Integer getIssueId() { + return issueId; + } + + public String getComment() { + return comment; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2125/Issue2125ErroneousMapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2125/Issue2125ErroneousMapper.java new file mode 100644 index 000000000..bdca17200 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2125/Issue2125ErroneousMapper.java @@ -0,0 +1,28 @@ +/* + * 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.bugs._2125; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; + +@Mapper +public interface Issue2125ErroneousMapper { + + @Mapping(target = "issueId", qualifiedByName = "mapIssueNumber") + @Mapping( target = "comment", ignore = true) + Comment clone(Repository repository); + + @Mapping(target = "issueId", qualifiedByName = "mapIssueNumber") + @Mapping( target = "comment", ignore = true) + Comment clone(Comment comment, Repository repository); + + @Named("mapIssueNumber") + default Integer mapIssueNumber(Integer issueNumber) { + return issueNumber != null ? issueNumber + 1 : null; + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2125/Issue2125Mapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2125/Issue2125Mapper.java new file mode 100644 index 000000000..3a867baf4 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2125/Issue2125Mapper.java @@ -0,0 +1,28 @@ +/* + * 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.bugs._2125; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface Issue2125Mapper { + + Issue2125Mapper INSTANCE = Mappers.getMapper( Issue2125Mapper.class ); + + Comment clone(Comment comment, Integer issueId); + + @Mapping(target = "issueId", qualifiedByName = "mapIssueNumber") + Comment cloneWithQualifier(Comment comment, Integer issueId); + + @Named("mapIssueNumber") + default Integer mapIssueNumber(Integer issueNumber) { + return issueNumber != null ? issueNumber + 1 : null; + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2125/Issue2125Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2125/Issue2125Test.java new file mode 100644 index 000000000..38f235509 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2125/Issue2125Test.java @@ -0,0 +1,71 @@ +/* + * 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.bugs._2125; + +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.compilation.annotation.CompilationResult; +import org.mapstruct.ap.testutil.compilation.annotation.Diagnostic; +import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome; +import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +@IssueKey("2125") +@WithClasses({ + Comment.class, + Repository.class, +}) +@RunWith(AnnotationProcessorTestRunner.class) +public class Issue2125Test { + + @Test + @WithClasses({ + Issue2125Mapper.class + }) + public void shouldSelectProperMethod() { + + Comment comment = Issue2125Mapper.INSTANCE.clone( + new Comment( 2125, "Fix issue" ), + 1000 + ); + + assertThat( comment ).isNotNull(); + assertThat( comment.getIssueId() ).isEqualTo( 2125 ); + + comment = Issue2125Mapper.INSTANCE.cloneWithQualifier( + new Comment( 2125, "Fix issue" ), + 1000 + ); + + assertThat( comment ).isNotNull(); + assertThat( comment.getIssueId() ).isEqualTo( 1001 ); + } + + @Test + @WithClasses({ + Issue2125ErroneousMapper.class + }) + @ExpectedCompilationOutcome(value = CompilationResult.FAILED, + diagnostics = { + @Diagnostic(type = Issue2125ErroneousMapper.class, + kind = javax.tools.Diagnostic.Kind.ERROR, + line = 15, + alternativeLine = 17, // For some reason javac reports the error on the method instead of the annotation + message = "The type of parameter \"repository\" has no property named \"issueId\". Please define the " + + "source property explicitly."), + @Diagnostic(type = Issue2125ErroneousMapper.class, + kind = javax.tools.Diagnostic.Kind.ERROR, + line = 19, + alternativeLine = 21, // For some reason javac reports the error on the method instead of the annotation + message = "No property named \"issueId\" exists in source parameter(s). Please define the source " + + "explicitly.") + }) + public void shouldReportErrorWhenMultipleSourcesMatch() { + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2125/Repository.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2125/Repository.java new file mode 100644 index 000000000..bf0c80984 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2125/Repository.java @@ -0,0 +1,28 @@ +/* + * 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.bugs._2125; + +/** + * @author Filip Hrisafov + */ +public class Repository { + + private final String owner; + private final String name; + + public Repository(String owner, String name) { + this.owner = owner; + this.name = name; + } + + public String getOwner() { + return owner; + } + + public String getName() { + return name; + } +}