#104 Fixing issue which prevented the mapping of a property which has no setter in the source and is named as source via @Mapping

This commit is contained in:
Gunnar Morling 2014-01-21 22:42:55 +01:00
parent 196d91324a
commit 5dd3ab2bec
6 changed files with 58 additions and 14 deletions

View File

@ -32,6 +32,10 @@ import org.mapstruct.ap.util.Strings;
/** /**
* Represents a mapping method with source and target type and the mappings between the properties of source and target * Represents a mapping method with source and target type and the mappings between the properties of source and target
* type. * type.
* <p>
* A method can either be configured by itself or by another method for the inverse mapping direction (one of
* {@link #setMappings(Map)}, {@link #setIterableMapping(IterableMapping)} or {@link #setMapMapping(MapMapping)} will be
* called in this case).
* *
* @author Gunnar Morling * @author Gunnar Morling
*/ */
@ -40,13 +44,14 @@ public class Method {
private final Type declaringMapper; private final Type declaringMapper;
private final ExecutableElement executable; private final ExecutableElement executable;
private final List<Parameter> parameters; private final List<Parameter> parameters;
private final Parameter targetParameter;
private final Type returnType; private final Type returnType;
private Map<String, List<Mapping>> mappings; private Map<String, List<Mapping>> mappings;
private IterableMapping iterableMapping; private IterableMapping iterableMapping;
private MapMapping mapMapping; private MapMapping mapMapping;
private final Parameter targetParameter; private boolean configuredByReverseMappingMethod = false;
public static Method forMethodRequiringImplementation(ExecutableElement executable, List<Parameter> parameters, public static Method forMethodRequiringImplementation(ExecutableElement executable, List<Parameter> parameters,
Type returnType, Map<String, List<Mapping>> mappings, Type returnType, Map<String, List<Mapping>> mappings,
@ -150,6 +155,7 @@ public class Method {
public void setMappings(Map<String, List<Mapping>> mappings) { public void setMappings(Map<String, List<Mapping>> mappings) {
this.mappings = mappings; this.mappings = mappings;
this.configuredByReverseMappingMethod = true;
} }
public IterableMapping getIterableMapping() { public IterableMapping getIterableMapping() {
@ -158,6 +164,7 @@ public class Method {
public void setIterableMapping(IterableMapping iterableMapping) { public void setIterableMapping(IterableMapping iterableMapping) {
this.iterableMapping = iterableMapping; this.iterableMapping = iterableMapping;
this.configuredByReverseMappingMethod = true;
} }
public MapMapping getMapMapping() { public MapMapping getMapMapping() {
@ -166,6 +173,7 @@ public class Method {
public void setMapMapping(MapMapping mapMapping) { public void setMapMapping(MapMapping mapMapping) {
this.mapMapping = mapMapping; this.mapMapping = mapMapping;
this.configuredByReverseMappingMethod = true;
} }
public boolean reverses(Method method) { public boolean reverses(Method method) {
@ -188,6 +196,15 @@ public class Method {
&& getResultType().isMapType(); && getResultType().isMapType();
} }
/**
* Whether this method is configured by itself or by the corresponding reverse mapping method.
*
* @return {@code true} if this method is configured by itself, {@code false} otherwise.
*/
public boolean isConfiguredByReverseMappingMethod() {
return configuredByReverseMappingMethod;
}
private boolean equals(Object o1, Object o2) { private boolean equals(Object o1, Object o2) {
return ( o1 == null && o2 == null ) || ( o1 != null ) && o1.equals( o2 ); return ( o1 == null && o2 == null ) || ( o1 != null ) && o1.equals( o2 );
} }

View File

@ -27,7 +27,6 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.annotation.processing.Messager; import javax.annotation.processing.Messager;
import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeElement;
@ -377,7 +376,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
private boolean hasSourceProperty(Method method, String propertyName) { private boolean hasSourceProperty(Method method, String propertyName) {
for ( Parameter parameter : method.getSourceParameters() ) { for ( Parameter parameter : method.getSourceParameters() ) {
if ( hasProperty( parameter, propertyName ) ) { if ( hasSourceProperty( parameter, propertyName ) ) {
return true; return true;
} }
} }
@ -385,20 +384,21 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
return false; return false;
} }
private boolean hasProperty(Parameter parameter, String propertyName) { private boolean hasSourceProperty(Parameter parameter, String propertyName) {
TypeElement parameterTypeElement = parameter.getType().getTypeElement(); TypeElement parameterTypeElement = parameter.getType().getTypeElement();
List<ExecutableElement> targetAccessors = filters.setterMethodsIn( List<ExecutableElement> getters = filters.getterMethodsIn(
elementUtils.getAllMembers( parameterTypeElement ) elementUtils.getAllMembers( parameterTypeElement )
); );
targetAccessors.addAll(
filters.alternativeTargetAccessorMethodsIn( return executables.getPropertyNames( getters ).contains( propertyName );
elementUtils.getAllMembers( parameterTypeElement )
)
);
return executables.getPropertyNames( targetAccessors ).contains( propertyName );
} }
private boolean reportErrorIfMappedPropertiesDontExist(Method method) { private boolean reportErrorIfMappedPropertiesDontExist(Method method) {
// only report errors if this method itself is configured
if ( method.isConfiguredByReverseMappingMethod() ) {
return true;
}
TypeElement resultTypeElement = method.getResultType().getTypeElement(); TypeElement resultTypeElement = method.getResultType().getTypeElement();
List<ExecutableElement> targetAccessors = filters.setterMethodsIn( List<ExecutableElement> targetAccessors = filters.setterMethodsIn(
elementUtils.getAllMembers( resultTypeElement ) elementUtils.getAllMembers( resultTypeElement )
@ -431,7 +431,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
foundUnmappedProperty = true; foundUnmappedProperty = true;
} }
else { else {
if ( !hasProperty( sourceParameter, mappedProperty.getSourcePropertyName() ) ) { if ( !hasSourceProperty( sourceParameter, mappedProperty.getSourcePropertyName() ) ) {
messager.printMessage( messager.printMessage(
Kind.ERROR, Kind.ERROR,
String.format( String.format(

View File

@ -55,4 +55,15 @@ public class OnewayTest extends MapperTestBase {
assertThat( source ).isNotNull(); assertThat( source ).isNotNull();
assertThat( source.retrieveBar() ).isEqualTo( 23 ); assertThat( source.retrieveBar() ).isEqualTo( 23 );
} }
@Test
@IssueKey("104")
public void shouldMapMappedAttributeWithoutSetterInSourceType() {
Source source = new Source();
Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source );
assertThat( target ).isNotNull();
assertThat( target.getQux() ).isEqualTo( 23L );
}
} }

View File

@ -20,8 +20,9 @@ package org.mapstruct.ap.test.oneway;
public class Source { public class Source {
private int foo = 42; private final int foo = 42;
private int bar; private int bar;
private final long qax = 23L;
public int getFoo() { public int getFoo() {
return foo; return foo;
@ -34,4 +35,8 @@ public class Source {
public int retrieveBar() { public int retrieveBar() {
return bar; return bar;
} }
public long getQax() {
return qax;
}
} }

View File

@ -19,6 +19,7 @@
package org.mapstruct.ap.test.oneway; package org.mapstruct.ap.test.oneway;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
@Mapper @Mapper
@ -26,6 +27,7 @@ public interface SourceTargetMapper {
SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class ); SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class );
@Mapping(source = "qax", target = "qux")
Target sourceToTarget(Source source); Target sourceToTarget(Source source);
Source targetToSource(Target target); Source targetToSource(Target target);

View File

@ -21,7 +21,8 @@ package org.mapstruct.ap.test.oneway;
public class Target { public class Target {
private Long foo; private Long foo;
private int bar = 23; private final int bar = 23;
private long qux;
public void setFoo(Long foo) { public void setFoo(Long foo) {
this.foo = foo; this.foo = foo;
@ -34,4 +35,12 @@ public class Target {
public int getBar() { public int getBar() {
return bar; return bar;
} }
public void setQux(long qux) {
this.qux = qux;
}
public long getQux() {
return qux;
}
} }