diff --git a/.gitignore b/.gitignore index 606fc5526..a18a87059 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ .classpath .project .settings +.factorypath # IntelliJ *.iml diff --git a/processor/src/main/java/org/mapstruct/ap/MapperGenerationVisitor.java b/processor/src/main/java/org/mapstruct/ap/MapperGenerationVisitor.java index 35b18af3a..deea4b9cd 100644 --- a/processor/src/main/java/org/mapstruct/ap/MapperGenerationVisitor.java +++ b/processor/src/main/java/org/mapstruct/ap/MapperGenerationVisitor.java @@ -29,6 +29,8 @@ import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; @@ -358,19 +360,24 @@ public class MapperGenerationVisitor extends ElementKindVisitor6 { for ( ExecutableElement method : methodsIn( element.getEnclosedElements() ) ) { Parameter parameter = retrieveParameter( method ); Type returnType = retrieveReturnType( method ); + boolean mappingErroneous = false; if ( declaringMapper == null ) { if ( parameter.getType().isIterableType() && !returnType.isIterableType() ) { reportError( "Can't generate mapping method from iterable type to non-iterable ype.", method ); + mappingErroneous = true; } if ( !parameter.getType().isIterableType() && returnType.isIterableType() ) { reportError( "Can't generate mapping method from non-iterable type to iterable ype.", method ); + mappingErroneous = true; } if ( parameter.getType().isPrimitive() ) { reportError( "Can't generate mapping method with primitive parameter type.", method ); + mappingErroneous = true; } if ( returnType.isPrimitive() ) { reportError( "Can't generate mapping method with primitive return type.", method ); + mappingErroneous = true; } if ( mappingErroneous ) { @@ -432,15 +439,16 @@ public class MapperGenerationVisitor extends ElementKindVisitor6 { Element parameterElement = typeUtils.asElement( method.getParameters().get( 0 ).asType() ); List properties = new ArrayList(); + List sourceGetters = Filters.getterMethodsIn( parameterElement.getEnclosedElements() ); + List targetSetters = Filters.setterMethodsIn( returnTypeElement.getEnclosedElements() ); - for ( ExecutableElement getterMethod : Filters.getterMethodsIn( parameterElement.getEnclosedElements() ) ) { + reportErrorIfMappedPropertiesDontExist( method, mappings, sourceGetters, targetSetters ); + for ( ExecutableElement getterMethod : sourceGetters ) { String sourcePropertyName = Executables.getPropertyName( getterMethod ); Mapping mapping = mappings.get( sourcePropertyName ); - for ( ExecutableElement setterMethod :Filters.setterMethodsIn( returnTypeElement - .getEnclosedElements() ) ) { - + for ( ExecutableElement setterMethod : targetSetters ) { String targetPropertyName = Executables.getPropertyName( setterMethod ); if ( targetPropertyName.equals( mapping != null ? mapping.getTargetName() : sourcePropertyName ) ) { @@ -467,6 +475,45 @@ public class MapperGenerationVisitor extends ElementKindVisitor6 { return properties; } + private void reportErrorIfMappedPropertiesDontExist(ExecutableElement method, Map mappings, + List sourceGetters, + List targetSetters) { + + Set sourcePropertyNames = getPropertyNames( sourceGetters ); + Set targetPropertyNames = getPropertyNames( targetSetters ); + + for ( Mapping mappedProperty : mappings.values() ) { + if ( !sourcePropertyNames.contains( mappedProperty.getSourceName() ) ) { + reportError( + String.format( + "Unknown property \"%s\" in parameter type %s.", + mappedProperty.getSourceName(), + retrieveParameter( method ).getType() + ), method, mappedProperty.getMirror(), mappedProperty.getSourceAnnotationValue() + ); + } + if ( !targetPropertyNames.contains( mappedProperty.getTargetName() ) ) { + reportError( + String.format( + "Unknown property \"%s\" in return type %s.", + mappedProperty.getTargetName(), + retrieveReturnType( method ) + ), method, mappedProperty.getMirror(), mappedProperty.getTargetAnnotationValue() + ); + } + } + } + + private Set getPropertyNames(List propertyAccessors) { + Set propertyNames = new HashSet(); + + for ( ExecutableElement executableElement : propertyAccessors ) { + propertyNames.add( Executables.getPropertyName( executableElement ) ); + } + + return propertyNames; + } + private Map getMappings(MappingsPrism mappingsAnnotation) { Map mappings = new HashMap(); @@ -478,7 +525,13 @@ public class MapperGenerationVisitor extends ElementKindVisitor6 { } private Mapping getMapping(MappingPrism mapping) { - return new Mapping( mapping.source(), mapping.target() ); + return new Mapping( + mapping.source(), + mapping.target(), + mapping.mirror, + mapping.values.source(), + mapping.values.target() + ); } private Parameter retrieveParameter(ExecutableElement method) { @@ -505,4 +558,11 @@ public class MapperGenerationVisitor extends ElementKindVisitor6 { processingEnvironment.getMessager().printMessage( Kind.ERROR, message, element ); mappingErroneous = true; } + + private void reportError(String message, Element element, AnnotationMirror annotationMirror, + AnnotationValue annotationValue) { + processingEnvironment.getMessager() + .printMessage( Kind.ERROR, message, element, annotationMirror, annotationValue ); + mappingErroneous = true; + } } diff --git a/processor/src/main/java/org/mapstruct/ap/model/Type.java b/processor/src/main/java/org/mapstruct/ap/model/Type.java index a868391ad..07d726838 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/Type.java +++ b/processor/src/main/java/org/mapstruct/ap/model/Type.java @@ -39,9 +39,9 @@ public class Type implements Comparable { ); private static final ConcurrentMap DEFAULT_ITERABLE_IMPLEMENTATION_TYPES = - new ConcurrentHashMap(); + new ConcurrentHashMap(); private static final ConcurrentMap DEFAULT_COLLECTION_IMPLEMENTATION_TYPES = - new ConcurrentHashMap(); + new ConcurrentHashMap(); static { DEFAULT_COLLECTION_IMPLEMENTATION_TYPES.put( List.class.getName(), forClass( ArrayList.class ) ); diff --git a/processor/src/main/java/org/mapstruct/ap/model/source/Mapping.java b/processor/src/main/java/org/mapstruct/ap/model/source/Mapping.java index 0f748b2c3..1dbdb15a4 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/source/Mapping.java +++ b/processor/src/main/java/org/mapstruct/ap/model/source/Mapping.java @@ -18,14 +18,24 @@ */ package org.mapstruct.ap.model.source; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; + public class Mapping { private final String sourceName; private final String targetName; + private final AnnotationMirror mirror; + private final AnnotationValue sourceAnnotationValue; + private final AnnotationValue targetAnnotationValue; - public Mapping(String sourceName, String targetName) { + public Mapping(String sourceName, String targetName, AnnotationMirror mirror, AnnotationValue sourceAnnotationValue, + AnnotationValue targetAnnotationValue) { this.sourceName = sourceName; this.targetName = targetName; + this.mirror = mirror; + this.sourceAnnotationValue = sourceAnnotationValue; + this.targetAnnotationValue = targetAnnotationValue; } public String getSourceName() { @@ -36,6 +46,18 @@ public class Mapping { return targetName; } + public AnnotationMirror getMirror() { + return mirror; + } + + public AnnotationValue getSourceAnnotationValue() { + return sourceAnnotationValue; + } + + public AnnotationValue getTargetAnnotationValue() { + return targetAnnotationValue; + } + @Override public String toString() { return "Mapping {" + diff --git a/processor/src/main/java/org/mapstruct/ap/model/source/Parameter.java b/processor/src/main/java/org/mapstruct/ap/model/source/Parameter.java index e4edf7947..3d65e1c5d 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/source/Parameter.java +++ b/processor/src/main/java/org/mapstruct/ap/model/source/Parameter.java @@ -37,4 +37,9 @@ public class Parameter { public Type getType() { return type; } + + @Override + public String toString() { + return type.toString() + " " + name; + } } diff --git a/processor/src/test/java/org/mapstruct/ap/test/erroneous/attributereference/AnotherTarget.java b/processor/src/test/java/org/mapstruct/ap/test/erroneous/attributereference/AnotherTarget.java new file mode 100644 index 000000000..dabb0b342 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/erroneous/attributereference/AnotherTarget.java @@ -0,0 +1,32 @@ +/** + * Copyright 2012-2013 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.erroneous.attributereference; + +public class AnotherTarget { + + private int foo; + + public int getFoo() { + return foo; + } + + public void setFoo(int foo) { + this.foo = foo; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/erroneous/attributereference/ErroneousMapper.java b/processor/src/test/java/org/mapstruct/ap/test/erroneous/attributereference/ErroneousMapper.java new file mode 100644 index 000000000..47d15e78a --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/erroneous/attributereference/ErroneousMapper.java @@ -0,0 +1,32 @@ +/** + * Copyright 2012-2013 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.erroneous.attributereference; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper +public interface ErroneousMapper { + + @Mapping(source = "foo", target = "bar") + Target sourceToTarget(Source source); + + @Mapping(source = "bar", target = "foo") + AnotherTarget sourceToAnotherTarget(Source source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/erroneous/attributereference/ErroneousMappingsTest.java b/processor/src/test/java/org/mapstruct/ap/test/erroneous/attributereference/ErroneousMappingsTest.java new file mode 100644 index 000000000..1372c241c --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/erroneous/attributereference/ErroneousMappingsTest.java @@ -0,0 +1,45 @@ +/** + * Copyright 2012-2013 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.erroneous.attributereference; + +import javax.tools.Diagnostic.Kind; + +import org.mapstruct.ap.testutil.IssueKey; +import org.mapstruct.ap.testutil.MapperTestBase; +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.testng.annotations.Test; + +@WithClasses({ ErroneousMapper.class, Source.class, Target.class, AnotherTarget.class }) +public class ErroneousMappingsTest extends MapperTestBase { + + @Test + @IssueKey("11") + @ExpectedCompilationOutcome( + value = CompilationResult.FAILED, + diagnostics = { + @Diagnostic(type = ErroneousMapper.class, kind = Kind.ERROR, line = 27), + @Diagnostic(type = ErroneousMapper.class, kind = Kind.ERROR, line = 30) + } + ) + public void shouldFailToGenerateMappings() { + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/erroneous/attributereference/Source.java b/processor/src/test/java/org/mapstruct/ap/test/erroneous/attributereference/Source.java new file mode 100644 index 000000000..75b967caf --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/erroneous/attributereference/Source.java @@ -0,0 +1,32 @@ +/** + * Copyright 2012-2013 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.erroneous.attributereference; + +public class Source { + + private int foo; + + public int getFoo() { + return foo; + } + + public void setFoo(int foo) { + this.foo = foo; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/erroneous/attributereference/Target.java b/processor/src/test/java/org/mapstruct/ap/test/erroneous/attributereference/Target.java new file mode 100644 index 000000000..e7830660e --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/erroneous/attributereference/Target.java @@ -0,0 +1,32 @@ +/** + * Copyright 2012-2013 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.erroneous.attributereference; + +public class Target { + + private int foo; + + public int getFoo() { + return foo; + } + + public void setFoo(int foo) { + this.foo = foo; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/erroneous/ErroneousMapper.java b/processor/src/test/java/org/mapstruct/ap/test/erroneous/typemismatch/ErroneousMapper.java similarity index 95% rename from processor/src/test/java/org/mapstruct/ap/test/erroneous/ErroneousMapper.java rename to processor/src/test/java/org/mapstruct/ap/test/erroneous/typemismatch/ErroneousMapper.java index 9041587b5..4f64df713 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/erroneous/ErroneousMapper.java +++ b/processor/src/test/java/org/mapstruct/ap/test/erroneous/typemismatch/ErroneousMapper.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.mapstruct.ap.test.erroneous; +package org.mapstruct.ap.test.erroneous.typemismatch; import org.mapstruct.Mapper; diff --git a/processor/src/test/java/org/mapstruct/ap/test/erroneous/ErroneousMappingsTest.java b/processor/src/test/java/org/mapstruct/ap/test/erroneous/typemismatch/ErroneousMappingsTest.java similarity index 97% rename from processor/src/test/java/org/mapstruct/ap/test/erroneous/ErroneousMappingsTest.java rename to processor/src/test/java/org/mapstruct/ap/test/erroneous/typemismatch/ErroneousMappingsTest.java index c869a9ccb..52dae78c2 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/erroneous/ErroneousMappingsTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/erroneous/typemismatch/ErroneousMappingsTest.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.mapstruct.ap.test.erroneous; +package org.mapstruct.ap.test.erroneous.typemismatch; import javax.tools.Diagnostic.Kind; diff --git a/processor/src/test/java/org/mapstruct/ap/test/erroneous/Source.java b/processor/src/test/java/org/mapstruct/ap/test/erroneous/typemismatch/Source.java similarity index 94% rename from processor/src/test/java/org/mapstruct/ap/test/erroneous/Source.java rename to processor/src/test/java/org/mapstruct/ap/test/erroneous/typemismatch/Source.java index 9990cabe6..a5706a75e 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/erroneous/Source.java +++ b/processor/src/test/java/org/mapstruct/ap/test/erroneous/typemismatch/Source.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.mapstruct.ap.test.erroneous; +package org.mapstruct.ap.test.erroneous.typemismatch; public class Source { diff --git a/processor/src/test/java/org/mapstruct/ap/test/erroneous/Target.java b/processor/src/test/java/org/mapstruct/ap/test/erroneous/typemismatch/Target.java similarity index 94% rename from processor/src/test/java/org/mapstruct/ap/test/erroneous/Target.java rename to processor/src/test/java/org/mapstruct/ap/test/erroneous/typemismatch/Target.java index 3a47e2fbe..a0c3fd14e 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/erroneous/Target.java +++ b/processor/src/test/java/org/mapstruct/ap/test/erroneous/typemismatch/Target.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.mapstruct.ap.test.erroneous; +package org.mapstruct.ap.test.erroneous.typemismatch; public class Target {