From 2fe7f6be2b33ddd2a7de5ae207847478887d6b8f Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Tue, 24 Apr 2018 21:39:28 +0200 Subject: [PATCH] #1387 Improve error message when unknown source parameter is used in Mapping --- .../model/source/SourceReference.java | 16 +++++++++- .../mapstruct/ap/internal/util/Message.java | 2 +- .../mapstruct/ap/internal/util/Strings.java | 8 +++-- .../ErroneousSourceTargetMapper2.java | 30 +++++++++++++++++++ .../SeveralSourceParametersTest.java | 22 ++++++++++++++ 5 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/severalsources/ErroneousSourceTargetMapper2.java diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/SourceReference.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/SourceReference.java index 60353dc94..dba826683 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/SourceReference.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/SourceReference.java @@ -32,6 +32,7 @@ import javax.lang.model.type.DeclaredType; import org.mapstruct.ap.internal.model.common.Parameter; import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.common.TypeFactory; +import org.mapstruct.ap.internal.util.Extractor; import org.mapstruct.ap.internal.util.FormattingMessager; import org.mapstruct.ap.internal.util.Message; import org.mapstruct.ap.internal.util.Strings; @@ -132,7 +133,20 @@ public class SourceReference { String sourceParameterName = segments[0]; parameter = method.getSourceParameter( sourceParameterName ); if ( parameter == null ) { - reportMappingError( Message.PROPERTYMAPPING_INVALID_PARAMETER_NAME, sourceParameterName ); + reportMappingError( + Message.PROPERTYMAPPING_INVALID_PARAMETER_NAME, + sourceParameterName, + Strings.join( + method.getSourceParameters(), + ", ", + new Extractor() { + @Override + public String apply(Parameter parameter) { + return parameter.getName(); + } + } + ) + ); isValid = false; } } 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 3a65e30ce..fb1bdfcb9 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 @@ -59,7 +59,7 @@ public enum Message { PROPERTYMAPPING_DEFAULT_VALUE_AND_DEFAULT_EXPRESSION_BOTH_DEFINED( "Default value and default expression are both defined in @Mapping, either define a default value or a default expression." ), PROPERTYMAPPING_INVALID_EXPRESSION( "Value for expression must be given in the form \"java()\"." ), PROPERTYMAPPING_INVALID_DEFAULT_EXPRESSION( "Value for default expression must be given in the form \"java()\"." ), - PROPERTYMAPPING_INVALID_PARAMETER_NAME( "Method has no parameter named \"%s\"." ), + PROPERTYMAPPING_INVALID_PARAMETER_NAME( "Method has no source parameter named \"%s\". Method source parameters are: \"%s\"." ), PROPERTYMAPPING_NO_PROPERTY_IN_PARAMETER( "The type of parameter \"%s\" has no property named \"%s\"." ), PROPERTYMAPPING_INVALID_PROPERTY_NAME( "No property named \"%s\" exists in source parameter(s). Did you mean \"%s\"?" ), PROPERTYMAPPING_NO_PRESENCE_CHECKER_FOR_SOURCE_TYPE( "Using custom source value presence checking strategy, but no presence checker found for %s in source type." ), diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/Strings.java b/processor/src/main/java/org/mapstruct/ap/internal/util/Strings.java index a4a000ccc..a14e4d8ad 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/util/Strings.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/util/Strings.java @@ -98,10 +98,14 @@ public class Strings { } public static String join(Iterable iterable, String separator) { + return join( iterable, separator, null ); + } + + public static String join(Iterable iterable, String separator, Extractor extractor) { StringBuilder sb = new StringBuilder(); boolean isFirst = true; - for ( Object object : iterable ) { + for ( T object : iterable ) { if ( !isFirst ) { sb.append( separator ); } @@ -109,7 +113,7 @@ public class Strings { isFirst = false; } - sb.append( object ); + sb.append( extractor == null ? object : extractor.apply( object ) ); } return sb.toString(); diff --git a/processor/src/test/java/org/mapstruct/ap/test/severalsources/ErroneousSourceTargetMapper2.java b/processor/src/test/java/org/mapstruct/ap/test/severalsources/ErroneousSourceTargetMapper2.java new file mode 100644 index 000000000..0bf5ed252 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/severalsources/ErroneousSourceTargetMapper2.java @@ -0,0 +1,30 @@ +/** + * 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.severalsources; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.ReportingPolicy; + +@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface ErroneousSourceTargetMapper2 { + + @Mapping( target = "houseNumber", source = "houseNo") + DeliveryAddress addressAndAddressToDeliveryAddress(Address address, Person person); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/severalsources/SeveralSourceParametersTest.java b/processor/src/test/java/org/mapstruct/ap/test/severalsources/SeveralSourceParametersTest.java index f0e66c880..dcb0aaaef 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/severalsources/SeveralSourceParametersTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/severalsources/SeveralSourceParametersTest.java @@ -168,4 +168,26 @@ public class SeveralSourceParametersTest { }) public void shouldFailToGenerateMappingsForAmbigiousSourceProperty() { } + + @Test + @WithClasses({ + ErroneousSourceTargetMapper2.class, + Address.class, + Person.class, + DeliveryAddress.class + }) + @ExpectedCompilationOutcome( + value = CompilationResult.FAILED, + diagnostics = { + @Diagnostic( + type = ErroneousSourceTargetMapper2.class, + kind = Kind.ERROR, + line = 28, + messageRegExp = "Method has no source parameter named \"houseNo\"\\." + + " Method source parameters are: \"address, person\"\\." + ) + } + ) + public void shouldFailWhenSourcePropertyDoesNotMatchAnyOfTheSourceParameters() { + } }