#11 Raising an error when referencing unknown attribute in @Mapping

This commit is contained in:
Gunnar Morling 2013-06-02 15:47:14 +02:00
parent f5f448ab08
commit b3b90f7969
14 changed files with 273 additions and 12 deletions

1
.gitignore vendored
View File

@ -3,6 +3,7 @@
.classpath
.project
.settings
.factorypath
# IntelliJ
*.iml

View File

@ -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<Void, Void> {
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<Void, Void> {
Element parameterElement = typeUtils.asElement( method.getParameters().get( 0 ).asType() );
List<MappedProperty> properties = new ArrayList<MappedProperty>();
List<ExecutableElement> sourceGetters = Filters.getterMethodsIn( parameterElement.getEnclosedElements() );
List<ExecutableElement> 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<Void, Void> {
return properties;
}
private void reportErrorIfMappedPropertiesDontExist(ExecutableElement method, Map<String, Mapping> mappings,
List<ExecutableElement> sourceGetters,
List<ExecutableElement> targetSetters) {
Set<String> sourcePropertyNames = getPropertyNames( sourceGetters );
Set<String> 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<String> getPropertyNames(List<ExecutableElement> propertyAccessors) {
Set<String> propertyNames = new HashSet<String>();
for ( ExecutableElement executableElement : propertyAccessors ) {
propertyNames.add( Executables.getPropertyName( executableElement ) );
}
return propertyNames;
}
private Map<String, Mapping> getMappings(MappingsPrism mappingsAnnotation) {
Map<String, Mapping> mappings = new HashMap<String, Mapping>();
@ -478,7 +525,13 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
}
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<Void, Void> {
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;
}
}

View File

@ -39,9 +39,9 @@ public class Type implements Comparable<Type> {
);
private static final ConcurrentMap<String, Type> DEFAULT_ITERABLE_IMPLEMENTATION_TYPES =
new ConcurrentHashMap<String, Type>();
new ConcurrentHashMap<String, Type>();
private static final ConcurrentMap<String, Type> DEFAULT_COLLECTION_IMPLEMENTATION_TYPES =
new ConcurrentHashMap<String, Type>();
new ConcurrentHashMap<String, Type>();
static {
DEFAULT_COLLECTION_IMPLEMENTATION_TYPES.put( List.class.getName(), forClass( ArrayList.class ) );

View File

@ -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 {" +

View File

@ -37,4 +37,9 @@ public class Parameter {
public Type getType() {
return type;
}
@Override
public String toString() {
return type.toString() + " " + name;
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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() {
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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 {

View File

@ -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 {