diff --git a/documentation/src/main/asciidoc/mapstruct-reference-guide.asciidoc b/documentation/src/main/asciidoc/mapstruct-reference-guide.asciidoc index 765f6a4be..68f95a4df 100644 --- a/documentation/src/main/asciidoc/mapstruct-reference-guide.asciidoc +++ b/documentation/src/main/asciidoc/mapstruct-reference-guide.asciidoc @@ -3,6 +3,8 @@ :toc: right :sectanchors: :Author: Gunnar Morling, Andreas Gudian, Sjaak Derksen, Filip Hrisafov and the MapStruct community +:processor-dir: ../../../../processor +:processor-ap-test: {processor-dir}/src/test/java/org/mapstruct/ap/test [[Preface]] == Preface @@ -815,7 +817,7 @@ When generating the implementation of a mapping method, MapStruct will apply the * If source and target attribute have the same type, the value will be simply copied from source to target. If the attribute is a collection (e.g. a `List`) a copy of the collection will be set into the target attribute. * If source and target attribute type differ, check whether there is a another mapping method which has the type of the source attribute as parameter type and the type of the target attribute as return type. If such a method exists it will be invoked in the generated mapping implementation. * If no such method exists MapStruct will look whether a built-in conversion for the source and target type of the attribute exists. If this is the case, the generated mapping code will apply this conversion. -* If no such method was found MapStruct will try to generate an internal method that will do the mapping between the source and target attributes +* If no such method was found MapStruct will try to generate an automatic sub-mapping method that will do the mapping between the source and target attributes * If MapStruct could not create a name based mapping method an error will be raised at build time, indicating the non-mappable attribute and its path. include::controlling-nested-bean-mappings.asciidoc[] @@ -2458,9 +2460,64 @@ public class CustomAccessorNamingStrategy extends DefaultAccessorNamingStrategy ==== The `CustomAccessorNamingStrategy` makes use of the `DefaultAccessorNamingStrategy` (also available in mapstruct-processor) and relies on that class to leave most of the default behaviour unchanged. -To use a custom SPI implementation, it must be located in a seperate .jar file together with the file `META-INF/services/org.mapstruct.ap.spi.AccessorNamingStrategy` with the fully qualified name of your custom implementation as content (e.g. `org.mapstruct.example.CustomAccessorNamingStrategy`). This .jar file needs to be added to the annotation processor classpath (i.e. add it next to the place where you added the mapstruct-processor jar). +To use a custom SPI implementation, it must be located in a separate JAR file together with the file `META-INF/services/org.mapstruct.ap.spi.AccessorNamingStrategy` with the fully qualified name of your custom implementation as content (e.g. `org.mapstruct.example.CustomAccessorNamingStrategy`). This JAR file needs to be added to the annotation processor classpath (i.e. add it next to the place where you added the mapstruct-processor jar). [TIP] Fore more details: There's the above example is present in our our examples repository (https://github.com/mapstruct/mapstruct-examples). +[mapping-exclusion-provider] +=== Mapping Exclusion Provider +MapStruct offers the possibility to override the `MappingExclusionProvider` via the Service Provider Interface (SPI). +A nice example is to not allow MapStruct to create an automatic sub-mapping for a certain type, +i.e. MapStruct will not try to generate an automatic sub-mapping method for an excluded type. + +[NOTE] +==== +The `DefaultMappingExclusionProvider` will exclude all types under the `java` or `javax` packages. +This means that MapStruct will not try to generate an automatic sub-mapping method between some custom type and some type declared in the Java class library. +==== + +.Source object +==== +[source, java, linenums] +[subs="verbatim,attributes"] +---- +include::{processor-ap-test}/nestedbeans/exclusions/custom/Source.java[tag=documentation] +---- +==== + +.Target object +==== +[source, java, linenums] +[subs="verbatim,attributes"] +---- +include::{processor-ap-test}/nestedbeans/exclusions/custom/Target.java[tag=documentation] +---- +==== + +.Mapper definition +==== +[source, java, linenums] +[subs="verbatim,attributes"] +---- +include::{processor-ap-test}/nestedbeans/exclusions/custom/ErroneousCustomExclusionMapper.java[tag=documentation] +---- +==== + +We want to exclude the `NestedTarget` from the automatic sub-mapping method generation. + +.CustomMappingExclusionProvider +==== +[source, java, linenums] +[subs="verbatim,attributes"] +---- +include::{processor-ap-test}/nestedbeans/exclusions/custom/CustomMappingExclusionProvider.java[tag=documentation] +---- +==== + +To use a custom SPI implementation, it must be located in a separate JAR file +together with the file `META-INF/services/org.mapstruct.ap.spi.MappingExclusionProvider` with the fully qualified name of your custom implementation as content +(e.g. `org.mapstruct.example.CustomMappingExclusionProvider`). +This JAR file needs to be added to the annotation processor classpath +(i.e. add it next to the place where you added the mapstruct-processor jar). diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/AbstractBaseBuilder.java b/processor/src/main/java/org/mapstruct/ap/internal/model/AbstractBaseBuilder.java index 8f11684ab..55b0885b7 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/AbstractBaseBuilder.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/AbstractBaseBuilder.java @@ -50,7 +50,27 @@ class AbstractBaseBuilder> { return myself; } - boolean isDisableSubMappingMethodsGeneration() { + /** + * Checks if MapStruct is allowed to generate an automatic sub-mapping between {@code sourceType} and @{code + * targetType}. + * This will evaluate to {@code true}, when: + *
  • + * + * + *
  • + * + * @param sourceType candidate source type to generate a sub-mapping from + * @param targetType candidate target type to generate a sub-mapping for + * + * @return {@code true} if MapStruct can try to generate an automatic sub-mapping between the types. + */ + boolean canGenerateAutoSubMappingBetween(Type sourceType, Type targetType) { + return !isDisableSubMappingMethodsGeneration() && + ctx.canGenerateAutoSubMappingBetween( sourceType, targetType ); + } + + private boolean isDisableSubMappingMethodsGeneration() { MapperConfiguration configuration = MapperConfiguration.getInstanceOn( ctx.getMapperTypeElement() ); return configuration.isDisableSubMappingMethodsGeneration(); } @@ -123,11 +143,11 @@ class AbstractBaseBuilder> { * * @param method the method that should be mapped * @param sourceErrorMessagePart the error message part for the source - * @param sourceRHS the {@link SourceRHS} + * @param sourceType the source type of the mapping * @param targetType the type of the target mapping * @param targetPropertyName the name of the target property */ - void reportCannotCreateMapping(Method method, String sourceErrorMessagePart, SourceRHS sourceRHS, Type targetType, + void reportCannotCreateMapping(Method method, String sourceErrorMessagePart, Type sourceType, Type targetType, String targetPropertyName) { ctx.getMessager().printMessage( method.getExecutable(), @@ -136,7 +156,7 @@ class AbstractBaseBuilder> { targetType, targetPropertyName, targetType, - sourceRHS.getSourceType() /* original source type */ + sourceType ); } } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/AbstractMappingMethodBuilder.java b/processor/src/main/java/org/mapstruct/ap/internal/model/AbstractMappingMethodBuilder.java index 943724dba..da40bf0dd 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/AbstractMappingMethodBuilder.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/AbstractMappingMethodBuilder.java @@ -45,7 +45,7 @@ public abstract class AbstractMappingMethodBuilder + *
  • If source and target attribute have the same type, the value will be simply copied from source to target. + * If the attribute is a collection (e.g. a `List`) a copy of the collection will be set into the target + * attribute.
  • + *
  • If source and target attribute type differ, check whether there is a another mapping method which has the + * type of the source attribute as parameter type and the type of the target attribute as return type. If such a + * method exists it will be invoked in the generated mapping implementation.
  • + *
  • If no such method exists MapStruct will look whether a built-in conversion for the source and target type + * of the attribute exists. If this is the case, the generated mapping code will apply this conversion.
  • + *
  • If no such method was found MapStruct will try to generate an automatic sub-mapping method that will do + * the mapping between the source and target attributes
  • + *
  • If MapStruct could not create a name based mapping method an error will be raised at build time, + * indicating the non-mappable attribute and its path.
  • + * + * + * With this SPI the last step before raising an error can be controlled. i.e. A user can control whether MapStruct + * is allowed to generate such automatic sub-mapping method (for the source or target type) or not. + * + * @author Filip Hrisafov + * @since 1.2 + */ +@Experimental("This SPI can have it's signature changed in subsequent releases") +public interface MappingExclusionProvider { + + /** + * Checks if MapStruct should not generate an automatic sub-mapping for the provided {@link TypeElement}, i.e. + * MapStruct will not try to descent into this class and won't try to automatically map it with some other type. + * The given {@code typeElement} will be excluded from the automatic sub-mapping generation + * + * @param typeElement that needs to be checked + * + * @return {@code true} if MapStruct should exclude the provided {@link TypeElement} from an automatic sub-mapping + */ + boolean isExcluded(TypeElement typeElement); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/NoProperties.java b/processor/src/test/java/org/mapstruct/ap/test/NoProperties.java new file mode 100644 index 000000000..4a2c74081 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/NoProperties.java @@ -0,0 +1,25 @@ +/** + * 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; + +/** + * @author Filip Hrisafov + */ +public class NoProperties { +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/WithProperties.java b/processor/src/test/java/org/mapstruct/ap/test/WithProperties.java new file mode 100644 index 000000000..5d879dbdc --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/WithProperties.java @@ -0,0 +1,35 @@ +/** + * 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; + +/** + * @author Filip Hrisafov + */ +public class WithProperties { + + private String string; + + public String getString() { + return string; + } + + public void setString(String string) { + this.string = string; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/collection/erroneous/ErroneousCollectionMappingTest.java b/processor/src/test/java/org/mapstruct/ap/test/collection/erroneous/ErroneousCollectionMappingTest.java index 46544819e..5f7677594 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/collection/erroneous/ErroneousCollectionMappingTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/collection/erroneous/ErroneousCollectionMappingTest.java @@ -22,6 +22,8 @@ import javax.tools.Diagnostic.Kind; import org.junit.Test; import org.junit.runner.RunWith; +import org.mapstruct.ap.test.NoProperties; +import org.mapstruct.ap.test.WithProperties; import org.mapstruct.ap.testutil.IssueKey; import org.mapstruct.ap.testutil.WithClasses; import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult; @@ -108,16 +110,16 @@ public class ErroneousCollectionMappingTest { @Test @IssueKey("459") - @WithClasses({ ErroneousCollectionNoElementMappingFound.class }) + @WithClasses({ ErroneousCollectionNoElementMappingFound.class, NoProperties.class, WithProperties.class }) @ExpectedCompilationOutcome( value = CompilationResult.FAILED, diagnostics = { @Diagnostic(type = ErroneousCollectionNoElementMappingFound.class, kind = Kind.ERROR, - line = 37, - messageRegExp = - "Can't map Collection element \".*AttributedString attributedString\" to \".*String string\". " + - "Consider to declare/implement a mapping method: \".*String map(.*AttributedString value)") + line = 38, + messageRegExp = "Can't map Collection element \".*WithProperties withProperties\" to \".*NoProperties" + + " noProperties\". Consider to declare/implement a mapping method: \".*NoProperties map\\(" + + ".*WithProperties value\\)") } ) public void shouldFailOnNoElementMappingFound() { @@ -142,15 +144,16 @@ public class ErroneousCollectionMappingTest { @Test @IssueKey("459") - @WithClasses({ ErroneousCollectionNoKeyMappingFound.class }) + @WithClasses({ ErroneousCollectionNoKeyMappingFound.class, NoProperties.class, WithProperties.class }) @ExpectedCompilationOutcome( value = CompilationResult.FAILED, diagnostics = { @Diagnostic(type = ErroneousCollectionNoKeyMappingFound.class, kind = Kind.ERROR, - line = 37, - messageRegExp = "Can't map Map key \".*AttributedString attributedString\" to \".*String string\". " + - "Consider to declare/implement a mapping method: \".*String map(.*AttributedString value)") + line = 38, + messageRegExp = "Can't map Map key \".*WithProperties withProperties\" to \".*NoProperties " + + "noProperties\". Consider to declare/implement a mapping method: \".*NoProperties map\\(" + + ".*WithProperties value\\)") } ) public void shouldFailOnNoKeyMappingFound() { @@ -174,15 +177,16 @@ public class ErroneousCollectionMappingTest { @Test @IssueKey("459") - @WithClasses({ ErroneousCollectionNoValueMappingFound.class }) + @WithClasses({ ErroneousCollectionNoValueMappingFound.class, NoProperties.class, WithProperties.class }) @ExpectedCompilationOutcome( value = CompilationResult.FAILED, diagnostics = { @Diagnostic(type = ErroneousCollectionNoValueMappingFound.class, kind = Kind.ERROR, - line = 37, - messageRegExp = "Can't map Map value \".*AttributedString attributedString\" to \".*String string\". " + - "Consider to declare/implement a mapping method: \".*String map(.*AttributedString value)") + line = 38, + messageRegExp = "Can't map Map value \".*WithProperties withProperties\" to \".*NoProperties " + + "noProperties\". Consider to declare/implement a mapping method: \".*NoProperties map\\(" + + ".*WithProperties value\\)") } ) public void shouldFailOnNoValueMappingFound() { diff --git a/processor/src/test/java/org/mapstruct/ap/test/collection/erroneous/ErroneousCollectionNoElementMappingFound.java b/processor/src/test/java/org/mapstruct/ap/test/collection/erroneous/ErroneousCollectionNoElementMappingFound.java index d78ce5fb3..2b153913c 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/collection/erroneous/ErroneousCollectionNoElementMappingFound.java +++ b/processor/src/test/java/org/mapstruct/ap/test/collection/erroneous/ErroneousCollectionNoElementMappingFound.java @@ -18,10 +18,11 @@ */ package org.mapstruct.ap.test.collection.erroneous; -import java.text.AttributedString; import java.util.List; import org.mapstruct.Mapper; +import org.mapstruct.ap.test.NoProperties; +import org.mapstruct.ap.test.WithProperties; import org.mapstruct.factory.Mappers; /** @@ -34,6 +35,6 @@ public interface ErroneousCollectionNoElementMappingFound { ErroneousCollectionNoElementMappingFound INSTANCE = Mappers.getMapper( ErroneousCollectionNoElementMappingFound.class ); - List map(List source); + List map(List source); } diff --git a/processor/src/test/java/org/mapstruct/ap/test/collection/erroneous/ErroneousCollectionNoKeyMappingFound.java b/processor/src/test/java/org/mapstruct/ap/test/collection/erroneous/ErroneousCollectionNoKeyMappingFound.java index 4b5f74956..8891b2da9 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/collection/erroneous/ErroneousCollectionNoKeyMappingFound.java +++ b/processor/src/test/java/org/mapstruct/ap/test/collection/erroneous/ErroneousCollectionNoKeyMappingFound.java @@ -18,10 +18,11 @@ */ package org.mapstruct.ap.test.collection.erroneous; -import java.text.AttributedString; import java.util.Map; import org.mapstruct.Mapper; +import org.mapstruct.ap.test.NoProperties; +import org.mapstruct.ap.test.WithProperties; import org.mapstruct.factory.Mappers; /** @@ -34,6 +35,6 @@ public interface ErroneousCollectionNoKeyMappingFound { ErroneousCollectionNoKeyMappingFound INSTANCE = Mappers.getMapper( ErroneousCollectionNoKeyMappingFound.class ); - Map map(Map source); + Map map(Map source); } diff --git a/processor/src/test/java/org/mapstruct/ap/test/collection/erroneous/ErroneousCollectionNoValueMappingFound.java b/processor/src/test/java/org/mapstruct/ap/test/collection/erroneous/ErroneousCollectionNoValueMappingFound.java index a05de5427..9bfd418f3 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/collection/erroneous/ErroneousCollectionNoValueMappingFound.java +++ b/processor/src/test/java/org/mapstruct/ap/test/collection/erroneous/ErroneousCollectionNoValueMappingFound.java @@ -18,10 +18,11 @@ */ package org.mapstruct.ap.test.collection.erroneous; -import java.text.AttributedString; import java.util.Map; import org.mapstruct.Mapper; +import org.mapstruct.ap.test.NoProperties; +import org.mapstruct.ap.test.WithProperties; import org.mapstruct.factory.Mappers; /** @@ -34,6 +35,6 @@ public interface ErroneousCollectionNoValueMappingFound { ErroneousCollectionNoValueMappingFound INSTANCE = Mappers.getMapper( ErroneousCollectionNoValueMappingFound.class ); - Map map(Map source); + Map map(Map source); } diff --git a/processor/src/test/java/org/mapstruct/ap/test/java8stream/erroneous/ErroneousListToStreamNoElementMappingFound.java b/processor/src/test/java/org/mapstruct/ap/test/java8stream/erroneous/ErroneousListToStreamNoElementMappingFound.java index df8c7f182..31189594f 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/java8stream/erroneous/ErroneousListToStreamNoElementMappingFound.java +++ b/processor/src/test/java/org/mapstruct/ap/test/java8stream/erroneous/ErroneousListToStreamNoElementMappingFound.java @@ -18,11 +18,12 @@ */ package org.mapstruct.ap.test.java8stream.erroneous; -import java.text.AttributedString; import java.util.List; import java.util.stream.Stream; import org.mapstruct.Mapper; +import org.mapstruct.ap.test.NoProperties; +import org.mapstruct.ap.test.WithProperties; import org.mapstruct.factory.Mappers; /** @@ -34,5 +35,5 @@ public interface ErroneousListToStreamNoElementMappingFound { ErroneousListToStreamNoElementMappingFound INSTANCE = Mappers.getMapper( ErroneousListToStreamNoElementMappingFound.class ); - Stream mapCollectionToStream(List source); + Stream mapCollectionToStream(List source); } diff --git a/processor/src/test/java/org/mapstruct/ap/test/java8stream/erroneous/ErroneousStreamMappingTest.java b/processor/src/test/java/org/mapstruct/ap/test/java8stream/erroneous/ErroneousStreamMappingTest.java index ae35c3973..7122e730e 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/java8stream/erroneous/ErroneousStreamMappingTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/java8stream/erroneous/ErroneousStreamMappingTest.java @@ -22,6 +22,8 @@ import javax.tools.Diagnostic.Kind; import org.junit.Test; import org.junit.runner.RunWith; +import org.mapstruct.ap.test.NoProperties; +import org.mapstruct.ap.test.WithProperties; import org.mapstruct.ap.testutil.IssueKey; import org.mapstruct.ap.testutil.WithClasses; import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult; @@ -108,16 +110,16 @@ public class ErroneousStreamMappingTest { } @Test - @WithClasses({ ErroneousStreamToStreamNoElementMappingFound.class }) + @WithClasses({ ErroneousStreamToStreamNoElementMappingFound.class, NoProperties.class, WithProperties.class }) @ExpectedCompilationOutcome( value = CompilationResult.FAILED, diagnostics = { @Diagnostic(type = ErroneousStreamToStreamNoElementMappingFound.class, kind = Kind.ERROR, - line = 36, - messageRegExp = "Can't map Stream element \".*AttributedString attributedString\" to \".*String " + - "string\". Consider to declare/implement a mapping method: \".*String map(.*AttributedString " + - "value)") + line = 37, + messageRegExp = "Can't map Stream element \".*WithProperties withProperties\" to \".*NoProperties " + + "noProperties\". Consider to declare/implement a mapping method: \".*NoProperties map\\(" + + ".*WithProperties value\\)") } ) public void shouldFailOnNoElementMappingFoundForStreamToStream() { @@ -140,16 +142,17 @@ public class ErroneousStreamMappingTest { } @Test - @WithClasses({ ErroneousListToStreamNoElementMappingFound.class }) + @WithClasses({ ErroneousListToStreamNoElementMappingFound.class, NoProperties.class, WithProperties.class }) @ExpectedCompilationOutcome( value = CompilationResult.FAILED, diagnostics = { @Diagnostic(type = ErroneousListToStreamNoElementMappingFound.class, kind = Kind.ERROR, - line = 37, + line = 38, messageRegExp = - "Can't map Stream element \".*AttributedString attributedString\" to \".*String string\". " + - "Consider to declare/implement a mapping method: \".*String map\\(.*AttributedString value\\)") + "Can't map Stream element \".*WithProperties withProperties\" to \".*NoProperties noProperties\"." + + " Consider to declare/implement a mapping method: \".*NoProperties map\\(.*WithProperties " + + "value\\)") } ) public void shouldFailOnNoElementMappingFoundForListToStream() { @@ -172,16 +175,16 @@ public class ErroneousStreamMappingTest { } @Test - @WithClasses({ ErroneousStreamToListNoElementMappingFound.class }) + @WithClasses({ ErroneousStreamToListNoElementMappingFound.class, NoProperties.class, WithProperties.class }) @ExpectedCompilationOutcome( value = CompilationResult.FAILED, diagnostics = { @Diagnostic(type = ErroneousStreamToListNoElementMappingFound.class, kind = Kind.ERROR, - line = 37, + line = 38, messageRegExp = - "Can't map Stream element \".*AttributedString attributedString\" to .*String string\"." + - " Consider to declare/implement a mapping method: \".*String map(.*AttributedString value)") + "Can't map Stream element \".*WithProperties withProperties\" to .*NoProperties noProperties\"." + + " Consider to declare/implement a mapping method: \".*NoProperties map(.*WithProperties value)") } ) public void shouldFailOnNoElementMappingFoundForStreamToList() { diff --git a/processor/src/test/java/org/mapstruct/ap/test/java8stream/erroneous/ErroneousStreamToListNoElementMappingFound.java b/processor/src/test/java/org/mapstruct/ap/test/java8stream/erroneous/ErroneousStreamToListNoElementMappingFound.java index f3bc53466..8fd1b67e1 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/java8stream/erroneous/ErroneousStreamToListNoElementMappingFound.java +++ b/processor/src/test/java/org/mapstruct/ap/test/java8stream/erroneous/ErroneousStreamToListNoElementMappingFound.java @@ -18,11 +18,12 @@ */ package org.mapstruct.ap.test.java8stream.erroneous; -import java.text.AttributedString; import java.util.List; import java.util.stream.Stream; import org.mapstruct.Mapper; +import org.mapstruct.ap.test.NoProperties; +import org.mapstruct.ap.test.WithProperties; import org.mapstruct.factory.Mappers; /** @@ -34,5 +35,5 @@ public interface ErroneousStreamToListNoElementMappingFound { ErroneousStreamToListNoElementMappingFound INSTANCE = Mappers.getMapper( ErroneousStreamToListNoElementMappingFound.class ); - List mapStreamToCollection(Stream source); + List mapStreamToCollection(Stream source); } diff --git a/processor/src/test/java/org/mapstruct/ap/test/java8stream/erroneous/ErroneousStreamToStreamNoElementMappingFound.java b/processor/src/test/java/org/mapstruct/ap/test/java8stream/erroneous/ErroneousStreamToStreamNoElementMappingFound.java index 66cfcbbad..ac5d28a7a 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/java8stream/erroneous/ErroneousStreamToStreamNoElementMappingFound.java +++ b/processor/src/test/java/org/mapstruct/ap/test/java8stream/erroneous/ErroneousStreamToStreamNoElementMappingFound.java @@ -18,10 +18,11 @@ */ package org.mapstruct.ap.test.java8stream.erroneous; -import java.text.AttributedString; import java.util.stream.Stream; import org.mapstruct.Mapper; +import org.mapstruct.ap.test.NoProperties; +import org.mapstruct.ap.test.WithProperties; import org.mapstruct.factory.Mappers; /** @@ -33,5 +34,5 @@ public interface ErroneousStreamToStreamNoElementMappingFound { ErroneousStreamToStreamNoElementMappingFound INSTANCE = Mappers.getMapper( ErroneousStreamToStreamNoElementMappingFound.class ); - Stream mapStreamToStream(Stream source); + Stream mapStreamToStream(Stream source); } diff --git a/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/ErroneousJavaInternalMapper.java b/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/ErroneousJavaInternalMapper.java new file mode 100644 index 000000000..842199c46 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/ErroneousJavaInternalMapper.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.nestedbeans.exclusions; + +import org.mapstruct.Mapper; + +/** + * @author Filip Hrisafov + */ +@Mapper +public interface ErroneousJavaInternalMapper { + + Target map(Source entity); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/ErroneousJavaInternalTest.java b/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/ErroneousJavaInternalTest.java new file mode 100644 index 000000000..db2e37e71 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/ErroneousJavaInternalTest.java @@ -0,0 +1,65 @@ +/** + * 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.nestedbeans.exclusions; + +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; + +/** + * @author Filip Hrisafov + */ +@WithClasses({ + Source.class, + Target.class, + ErroneousJavaInternalMapper.class +}) +@RunWith(AnnotationProcessorTestRunner.class) +@IssueKey("1154") +public class ErroneousJavaInternalTest { + + @ExpectedCompilationOutcome(value = CompilationResult.FAILED, + diagnostics = { + @Diagnostic(type = ErroneousJavaInternalMapper.class, + kind = javax.tools.Diagnostic.Kind.ERROR, + line = 29, + messageRegExp = "Can't map property \".*MyType date\" to \"java\\.util\\.Date date\"\\. Consider to " + + "declare/implement a mapping method: \"java\\.util\\.Date map\\(.*MyType value\\)\"\\."), + @Diagnostic(type = ErroneousJavaInternalMapper.class, + kind = javax.tools.Diagnostic.Kind.ERROR, + line = 29, + messageRegExp = "Can't map property \".*MyType calendar\" to \"java\\.util\\.GregorianCalendar " + + "calendar\"\\. Consider to declare/implement a mapping method: \"java\\.util\\.GregorianCalendar " + + "map\\(.*MyType value\\)\"\\."), + @Diagnostic(type = ErroneousJavaInternalMapper.class, + kind = javax.tools.Diagnostic.Kind.ERROR, + line = 29, + messageRegExp = "Can't map property \".*List<.*MyType> types\" to \".*List<.*String> types\"\\" + + ". Consider to declare/implement a mapping method: \".*List<.*String> map\\(.*List<.*MyType> " + + "value\\)\"\\.") + }) + @Test + public void shouldNotNestIntoJavaPackageObjects() throws Exception { + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/Source.java b/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/Source.java new file mode 100644 index 000000000..da8e64d32 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/Source.java @@ -0,0 +1,54 @@ +/** + * 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.nestedbeans.exclusions; + +import java.util.List; + +/** + * @author Filip Hrisafov + */ +class Source { + + static class DeepNestedType { + //CHECKSTYLE:OFF + public List types; + //CHECKSTYLE:ON + } + + static class NestedMyType { + //CHECKSTYLE:OFF + public DeepNestedType deepNestedType; + //CHECKSTYLE:ON + } + + static class MyType { + //CHECKSTYLE:OFF + public String someProperty; + //CHECKSTYLE:ON + } + + //CHECKSTYLE:OFF + public MyType date; + public MyType calendar; + public List types; + //TODO Nested error messages do not work yet. I think that this should be solved as part of #1150 + // (or we solve that one first :)) + //public NestedMyType nestedMyType; + //CHECKSTYLE:ON +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/Target.java b/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/Target.java new file mode 100644 index 000000000..7ceedbd35 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/Target.java @@ -0,0 +1,48 @@ +/** + * 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.nestedbeans.exclusions; + +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.List; + +/** + * @author Filip Hrisafov + */ +class Target { + + class TargetDeepNested { + //CHECKSTYLE:OFF + public List types; + //CHECKSTYLE:ON + } + + class TargetNested { + //CHECKSTYLE:OFF + public TargetDeepNested deepNestedType; + //CHECKSTYLE:ON + } + + //CHECKSTYLE:OFF + public Date date; + public GregorianCalendar calendar; + public List types; + //public TargetNested nestedMyType; + //CHECKSTYLE:ON +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/custom/CustomMappingExclusionProvider.java b/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/custom/CustomMappingExclusionProvider.java new file mode 100644 index 000000000..ad3461ff5 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/custom/CustomMappingExclusionProvider.java @@ -0,0 +1,47 @@ +/** + * 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.nestedbeans.exclusions.custom; + +// tag::documentation[] + +import java.util.regex.Pattern; +import javax.lang.model.element.Name; +import javax.lang.model.element.TypeElement; + +import org.mapstruct.ap.spi.MappingExclusionProvider; + +// end::documentation[] +/** + * @author Filip Hrisafov + */ +// tag::documentation[] +public class CustomMappingExclusionProvider implements MappingExclusionProvider { + private static final Pattern JAVA_JAVAX_PACKAGE = Pattern.compile( "^javax?\\..*" ); + + @Override + public boolean isExcluded(TypeElement typeElement) { + // end::documentation[] + //For some reason the eclipse compiler does not work when you try to do NestedTarget.class + // tag::documentation[] + Name name = typeElement.getQualifiedName(); + return name.length() != 0 && ( JAVA_JAVAX_PACKAGE.matcher( name ).matches() || + name.toString().equals( "org.mapstruct.ap.test.nestedbeans.exclusions.custom.Target.NestedTarget" ) ); + } +} +// end::documentation[] diff --git a/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/custom/ErroneousCustomExclusionMapper.java b/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/custom/ErroneousCustomExclusionMapper.java new file mode 100644 index 000000000..51497f05b --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/custom/ErroneousCustomExclusionMapper.java @@ -0,0 +1,32 @@ +/** + * 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.nestedbeans.exclusions.custom; + +import org.mapstruct.Mapper; + +/** + * @author Filip Hrisafov + */ +// tag::documentation[] +@Mapper +public interface ErroneousCustomExclusionMapper { + + Target map(Source source); +} +// end::documentation[] diff --git a/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/custom/ErroneousCustomExclusionTest.java b/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/custom/ErroneousCustomExclusionTest.java new file mode 100644 index 000000000..3196bef2e --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/custom/ErroneousCustomExclusionTest.java @@ -0,0 +1,57 @@ +/** + * 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.nestedbeans.exclusions.custom; + +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.WithServiceImplementation; +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; + +/** + * @author Filip Hrisafov + */ +@WithClasses({ + Source.class, + Target.class, + ErroneousCustomExclusionMapper.class +}) +@WithServiceImplementation( CustomMappingExclusionProvider.class ) +@RunWith(AnnotationProcessorTestRunner.class) +@IssueKey("1154") +public class ErroneousCustomExclusionTest { + + @ExpectedCompilationOutcome(value = CompilationResult.FAILED, + diagnostics = { + @Diagnostic(type = ErroneousCustomExclusionMapper.class, + kind = javax.tools.Diagnostic.Kind.ERROR, + line = 30, + messageRegExp = "Can't map property \".*NestedSource nested\" to \".*NestedTarget nested\"\\. " + + "Consider to declare/implement a mapping method: \".*NestedTarget map\\(.*NestedSource value\\)" + + "\"\\.") + } + ) + @Test + public void shouldFailToCreateMappingForExcludedClass() { + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/custom/Source.java b/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/custom/Source.java new file mode 100644 index 000000000..969334da4 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/custom/Source.java @@ -0,0 +1,55 @@ +/** + * 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.nestedbeans.exclusions.custom; + +/** + * @author Filip Hrisafov + */ +// tag::documentation[] +public class Source { + + static class NestedSource { + private String property; + // getters and setters + // end::documentation[] + + public String getProperty() { + return property; + } + + public void setProperty(String property) { + this.property = property; + } + // tag::documentation[] + } + + private NestedSource nested; + // getters and setters + // end::documentation[] + + public NestedSource getNested() { + return nested; + } + + public void setNested(NestedSource nested) { + this.nested = nested; + } + // tag::documentation[] +} +// tag::documentation[] diff --git a/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/custom/Target.java b/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/custom/Target.java new file mode 100644 index 000000000..e6d4b1ef2 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/nestedbeans/exclusions/custom/Target.java @@ -0,0 +1,55 @@ +/** + * 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.nestedbeans.exclusions.custom; + +/** + * @author Filip Hrisafov + */ +// tag::documentation[] +public class Target { + + static class NestedTarget { + private String property; + // getters and setters + // end::documentation[] + + public String getProperty() { + return property; + } + + public void setProperty(String property) { + this.property = property; + } + // tag::documentation[] + } + + private NestedTarget nested; + // getters and setters + // end::documentation[] + + public NestedTarget getNested() { + return nested; + } + + public void setNested(NestedTarget nested) { + this.nested = nested; + } + // tag::documentation[] +} +// end::documentation[] diff --git a/processor/src/test/java/org/mapstruct/ap/test/selection/generics/ConversionTest.java b/processor/src/test/java/org/mapstruct/ap/test/selection/generics/ConversionTest.java index 9398e634b..67495c38c 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/selection/generics/ConversionTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/selection/generics/ConversionTest.java @@ -18,12 +18,11 @@ */ package org.mapstruct.ap.test.selection.generics; -import static org.assertj.core.api.Assertions.assertThat; - import java.math.BigDecimal; import org.junit.Test; import org.junit.runner.RunWith; +import org.mapstruct.ap.test.NoProperties; import org.mapstruct.ap.testutil.IssueKey; import org.mapstruct.ap.testutil.WithClasses; import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult; @@ -31,6 +30,8 @@ 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; + /** * Tests for the invocation of generic methods for mapping bean properties. * @@ -162,13 +163,18 @@ public class ConversionTest { } @Test - @WithClasses({ ErroneousSource6.class, ErroneousTarget6.class, ErroneousSourceTargetMapper6.class }) + @WithClasses({ + ErroneousSource6.class, + ErroneousTarget6.class, + ErroneousSourceTargetMapper6.class, + NoProperties.class + }) @ExpectedCompilationOutcome(value = CompilationResult.FAILED, diagnostics = { @Diagnostic(type = ErroneousSourceTargetMapper6.class, kind = javax.tools.Diagnostic.Kind.ERROR, line = 29, - messageRegExp = "Can't map property \"java.lang.String " + messageRegExp = "Can't map property \".*NoProperties " + "foo\\.wrapped\" to" + " \"org.mapstruct.ap.test.selection.generics.TypeA " + "foo\\.wrapped\"") diff --git a/processor/src/test/java/org/mapstruct/ap/test/selection/generics/ErroneousSource6.java b/processor/src/test/java/org/mapstruct/ap/test/selection/generics/ErroneousSource6.java index c4b3adefc..92662c8b7 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/selection/generics/ErroneousSource6.java +++ b/processor/src/test/java/org/mapstruct/ap/test/selection/generics/ErroneousSource6.java @@ -18,15 +18,17 @@ */ package org.mapstruct.ap.test.selection.generics; +import org.mapstruct.ap.test.NoProperties; + public class ErroneousSource6 { - private WildCardSuperWrapper foo; + private WildCardSuperWrapper foo; - public WildCardSuperWrapper getFoo() { + public WildCardSuperWrapper getFoo() { return foo; } - public void setFoo(WildCardSuperWrapper foo) { + public void setFoo(WildCardSuperWrapper foo) { this.foo = foo; } }