mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#574 determine property type from getter/setter methods only in combination with ExecutableType (i.e. using asMemberOf to determine the type with any generics being resolved)
This commit is contained in:
parent
a35cf3c16d
commit
264a8f65af
@ -33,6 +33,7 @@ import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
@ -404,9 +405,11 @@ public class BeanMappingMethod extends MappingMethod {
|
||||
if ( sourceAccessor != null ) {
|
||||
Mapping mapping = method.getSingleMappingByTargetPropertyName( targetProperty.getKey() );
|
||||
|
||||
TypeElement sourceType = sourceParameter.getType().getTypeElement();
|
||||
|
||||
SourceReference sourceRef = new SourceReference.BuilderFromProperty()
|
||||
.sourceParameter( sourceParameter )
|
||||
.type( ctx.getTypeFactory().getReturnType( sourceAccessor ) )
|
||||
.type( ctx.getTypeFactory().getReturnType( sourceType, sourceAccessor ) )
|
||||
.accessor( sourceAccessor )
|
||||
.name( targetProperty.getKey() )
|
||||
.build();
|
||||
|
@ -454,10 +454,14 @@ public class PropertyMapping extends ModelElement {
|
||||
switch ( targetAccessorType ) {
|
||||
case ADDER:
|
||||
case SETTER:
|
||||
return ctx.getTypeFactory().getSingleParameter( targetWriteAccessor ).getType();
|
||||
return ctx.getTypeFactory().getSingleParameter(
|
||||
method.getResultType().getTypeElement(),
|
||||
targetWriteAccessor ).getType();
|
||||
case GETTER:
|
||||
default:
|
||||
return ctx.getTypeFactory().getReturnType( targetWriteAccessor );
|
||||
return ctx.getTypeFactory().getReturnType(
|
||||
method.getResultType().getTypeElement(),
|
||||
targetWriteAccessor );
|
||||
}
|
||||
}
|
||||
|
||||
@ -570,10 +574,14 @@ public class PropertyMapping extends ModelElement {
|
||||
// target
|
||||
Type targetType;
|
||||
if ( Executables.isSetterMethod( targetWriteAccessor ) ) {
|
||||
targetType = ctx.getTypeFactory().getSingleParameter( targetWriteAccessor ).getType();
|
||||
targetType = ctx.getTypeFactory().getSingleParameter(
|
||||
method.getResultType().getTypeElement(),
|
||||
targetWriteAccessor ).getType();
|
||||
}
|
||||
else {
|
||||
targetType = ctx.getTypeFactory().getReturnType( targetWriteAccessor );
|
||||
targetType = ctx.getTypeFactory().getReturnType(
|
||||
method.getResultType().getTypeElement(),
|
||||
targetWriteAccessor );
|
||||
}
|
||||
|
||||
Assignment assignment = ctx.getMappingResolver().getTargetAssignment(
|
||||
@ -659,10 +667,14 @@ public class PropertyMapping extends ModelElement {
|
||||
if ( Executables.isSetterMethod( targetWriteAccessor ) ) {
|
||||
// setter, so wrap in setter
|
||||
assignment = new SetterWrapper( assignment, method.getThrownTypes() );
|
||||
targetType = ctx.getTypeFactory().getSingleParameter( targetWriteAccessor ).getType();
|
||||
targetType = ctx.getTypeFactory().getSingleParameter(
|
||||
method.getResultType().getTypeElement(),
|
||||
targetWriteAccessor ).getType();
|
||||
}
|
||||
else {
|
||||
targetType = ctx.getTypeFactory().getReturnType( targetWriteAccessor );
|
||||
targetType = ctx.getTypeFactory().getReturnType(
|
||||
method.getResultType().getTypeElement(),
|
||||
targetWriteAccessor );
|
||||
// target accessor is getter, so wrap the setter in getter map/ collection handling
|
||||
assignment = new GetterWrapperForCollectionsAndMaps(
|
||||
assignment,
|
||||
|
@ -398,7 +398,7 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
// first check if there's a setter method.
|
||||
ExecutableElement adderMethod = null;
|
||||
if ( Executables.isSetterMethod( candidate ) ) {
|
||||
Type targetType = typeFactory.getSingleParameter( candidate ).getType();
|
||||
Type targetType = typeFactory.getSingleParameter( typeElement, candidate ).getType();
|
||||
// ok, the current accessor is a setter. So now the strategy determines what to use
|
||||
if ( cmStrategy == CollectionMappingStrategyPrism.ADDER_PREFERRED ) {
|
||||
adderMethod = getAdderForType( targetType, targetPropertyName );
|
||||
@ -407,7 +407,7 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
else if ( Executables.isGetterMethod( candidate ) ) {
|
||||
// the current accessor is a getter (no setter available). But still, an add method is according
|
||||
// to the above strategy (SETTER_PREFERRED || ADDER_PREFERRED) preferred over the getter.
|
||||
Type targetType = typeFactory.getReturnType( candidate );
|
||||
Type targetType = typeFactory.getReturnType( typeFactory.getMethodType( typeElement, candidate ) );
|
||||
adderMethod = getAdderForType( targetType, targetPropertyName );
|
||||
}
|
||||
if ( adderMethod != null ) {
|
||||
|
@ -55,6 +55,7 @@ import javax.lang.model.util.Types;
|
||||
import org.mapstruct.ap.internal.prism.MappingTargetPrism;
|
||||
import org.mapstruct.ap.internal.prism.TargetTypePrism;
|
||||
import org.mapstruct.ap.internal.util.AnnotationProcessingException;
|
||||
import org.mapstruct.ap.internal.util.Collections;
|
||||
import org.mapstruct.ap.internal.util.SpecificCompilerWorkarounds;
|
||||
|
||||
import static org.mapstruct.ap.internal.util.SpecificCompilerWorkarounds.erasure;
|
||||
@ -254,18 +255,18 @@ public class TypeFactory {
|
||||
* Get the ExecutableType for given method as part of usedMapper. Possibly parameterized types in method declaration
|
||||
* will be evaluated to concrete types then.
|
||||
*
|
||||
* @param usedMapper the type declaring the method
|
||||
* @param includingType the type on which's scope the method type shall be evaluated
|
||||
* @param method the method
|
||||
* @return the ExecutableType representing the method as part of usedMapper
|
||||
*/
|
||||
public ExecutableType getMethodType(TypeElement usedMapper, ExecutableElement method) {
|
||||
DeclaredType asType = (DeclaredType) replaceTypeElementIfNecessary( elementUtils, usedMapper ).asType();
|
||||
public ExecutableType getMethodType(TypeElement includingType, ExecutableElement method) {
|
||||
DeclaredType asType = (DeclaredType) replaceTypeElementIfNecessary( elementUtils, includingType ).asType();
|
||||
TypeMirror asMemberOf = typeUtils.asMemberOf( asType, method );
|
||||
ExecutableType methodType = asMemberOf.accept( new ExecutableTypeRetrievalVisitor(), null );
|
||||
return methodType;
|
||||
}
|
||||
|
||||
public Parameter getSingleParameter(ExecutableElement method) {
|
||||
public Parameter getSingleParameter(TypeElement includingType, ExecutableElement method) {
|
||||
List<? extends VariableElement> parameters = method.getParameters();
|
||||
|
||||
if ( parameters.size() != 1 ) {
|
||||
@ -273,31 +274,11 @@ public class TypeFactory {
|
||||
return null;
|
||||
}
|
||||
|
||||
VariableElement parameter = parameters.get( 0 );
|
||||
|
||||
return new Parameter(
|
||||
parameter.getSimpleName().toString(),
|
||||
getType( parameter.asType() )
|
||||
);
|
||||
return Collections.first( getParameters( includingType, method ) );
|
||||
}
|
||||
|
||||
public List<Parameter> getParameters(ExecutableElement method) {
|
||||
List<? extends VariableElement> parameters = method.getParameters();
|
||||
List<Parameter> result = new ArrayList<Parameter>( parameters.size() );
|
||||
|
||||
for ( VariableElement parameter : parameters ) {
|
||||
result
|
||||
.add(
|
||||
new Parameter(
|
||||
parameter.getSimpleName().toString(),
|
||||
getType( parameter.asType() ),
|
||||
MappingTargetPrism.getInstanceOn( parameter ) != null,
|
||||
TargetTypePrism.getInstanceOn( parameter ) != null
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
public List<Parameter> getParameters(TypeElement includingType, ExecutableElement method) {
|
||||
return getParameters( getMethodType( includingType, method ), method );
|
||||
}
|
||||
|
||||
public List<Parameter> getParameters(ExecutableType methodType, ExecutableElement method) {
|
||||
@ -322,20 +303,16 @@ public class TypeFactory {
|
||||
return result;
|
||||
}
|
||||
|
||||
public Type getReturnType(ExecutableElement method) {
|
||||
return getType( method.getReturnType() );
|
||||
public Type getReturnType(TypeElement includingType, ExecutableElement method) {
|
||||
return getReturnType( getMethodType( includingType, method ) );
|
||||
}
|
||||
|
||||
public Type getReturnType(ExecutableType method) {
|
||||
return getType( method.getReturnType() );
|
||||
}
|
||||
|
||||
public List<Type> getThrownTypes(ExecutableElement method) {
|
||||
List<Type> thrownTypes = new ArrayList<Type>();
|
||||
for (TypeMirror exceptionType : method.getThrownTypes() ) {
|
||||
thrownTypes.add( getType( exceptionType ) );
|
||||
}
|
||||
return thrownTypes;
|
||||
public List<Type> getThrownTypes(TypeElement includingType, ExecutableElement method) {
|
||||
return getThrownTypes( getMethodType( includingType, method ) );
|
||||
}
|
||||
|
||||
public List<Type> getThrownTypes(ExecutableType method) {
|
||||
@ -488,4 +465,5 @@ public class TypeFactory {
|
||||
|
||||
return collectionOrMap;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
||||
|
||||
ExecutableType methodType = typeFactory.getMethodType( usedMapper, method );
|
||||
List<Parameter> parameters = typeFactory.getParameters( methodType, method );
|
||||
Type returnType = typeFactory.getReturnType( method );
|
||||
Type returnType = typeFactory.getReturnType( methodType );
|
||||
|
||||
boolean methodRequiresImplementation = method.getModifiers().contains( Modifier.ABSTRACT );
|
||||
boolean containsTargetTypeParameter = SourceMethod.containsTargetTypeParameter( parameters );
|
||||
|
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright 2012-2015 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.generics;
|
||||
|
||||
/**
|
||||
* @author Andreas Gudian
|
||||
*/
|
||||
public abstract class AbstractIdHoldingTo<ID> {
|
||||
private ID id;
|
||||
|
||||
public ID getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public void setId(ID id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright 2012-2015 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.generics;
|
||||
|
||||
|
||||
/**
|
||||
* @author Andreas Gudian
|
||||
*/
|
||||
public abstract class AbstractTo extends AbstractIdHoldingTo<Long> {
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright 2012-2015 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.generics;
|
||||
|
||||
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.runner.AnnotationProcessorTestRunner;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Andreas Gudian
|
||||
*
|
||||
*/
|
||||
@WithClasses({
|
||||
AbstractTo.class,
|
||||
AbstractIdHoldingTo.class,
|
||||
Source.class,
|
||||
SourceTargetMapper.class,
|
||||
TargetTo.class
|
||||
})
|
||||
@RunWith(AnnotationProcessorTestRunner.class)
|
||||
public class GenericsTest {
|
||||
|
||||
@Test
|
||||
@IssueKey("574")
|
||||
public void mapsIdCorrectly() {
|
||||
TargetTo target = new TargetTo();
|
||||
target.setId( 41L );
|
||||
assertThat( SourceTargetMapper.INSTANCE.toSource( target ).getId() ).isEqualTo( 41L );
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright 2012-2015 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.generics;
|
||||
|
||||
/**
|
||||
* @author Andreas Gudian
|
||||
*
|
||||
*/
|
||||
public class Source {
|
||||
private Long id;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright 2012-2015 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.generics;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* @author Andreas Gudian
|
||||
*
|
||||
*/
|
||||
@Mapper
|
||||
public abstract class SourceTargetMapper {
|
||||
|
||||
public static final SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class );
|
||||
|
||||
public abstract Source toSource(TargetTo target);
|
||||
|
||||
public abstract TargetTo toTarget(Source source);
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright 2012-2015 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.generics;
|
||||
|
||||
|
||||
/**
|
||||
* @author Andreas Gudian
|
||||
*
|
||||
*/
|
||||
public class TargetTo extends AbstractTo {
|
||||
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user