mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#127 Working around broken Eclipse implementation of Types#asMemberOf()
This commit is contained in:
parent
cce558827d
commit
f69069c2f8
@ -31,11 +31,8 @@ import javax.annotation.processing.Messager;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
import javax.lang.model.type.ExecutableType;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.util.ElementFilter;
|
||||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.Types;
|
||||
import javax.tools.Diagnostic.Kind;
|
||||
@ -818,20 +815,21 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
||||
private void reportErrorIfPropertyCanNotBeMapped(Method method, PropertyMapping property) {
|
||||
boolean collectionOrMapTargetTypeHasCompatibleConstructor = false;
|
||||
|
||||
if ( property.getTargetType().isCollectionType() || property.getTargetType().isMapType() ) {
|
||||
if ( property.getTargetType().getImplementationType() != null ) {
|
||||
collectionOrMapTargetTypeHasCompatibleConstructor = hasCompatibleConstructor(
|
||||
if ( property.getSourceType().isCollectionType() && property.getTargetType().isCollectionType() ) {
|
||||
collectionOrMapTargetTypeHasCompatibleConstructor = collectionTypeHasCompatibleConstructor(
|
||||
property.getSourceType(),
|
||||
property.getTargetType().getImplementationType()
|
||||
property.getTargetType().getImplementationType() != null ?
|
||||
property.getTargetType().getImplementationType() : property.getTargetType()
|
||||
);
|
||||
}
|
||||
else {
|
||||
collectionOrMapTargetTypeHasCompatibleConstructor = hasCompatibleConstructor(
|
||||
|
||||
if ( property.getSourceType().isMapType() && property.getTargetType().isMapType() ) {
|
||||
collectionOrMapTargetTypeHasCompatibleConstructor = mapTypeHasCompatibleConstructor(
|
||||
property.getSourceType(),
|
||||
property.getTargetType()
|
||||
property.getTargetType().getImplementationType() != null ?
|
||||
property.getTargetType().getImplementationType() : property.getTargetType()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( property.getSourceType().isAssignableTo( property.getTargetType() ) ||
|
||||
property.getMappingMethod() != null ||
|
||||
@ -863,31 +861,63 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
||||
* @return {@code true} if the target type has a constructor accepting the given source type, {@code false}
|
||||
* otherwise.
|
||||
*/
|
||||
private boolean hasCompatibleConstructor(Type sourceType, Type targetType) {
|
||||
List<ExecutableElement> targetTypeConstructors = ElementFilter.constructorsIn(
|
||||
targetType.getTypeElement()
|
||||
.getEnclosedElements()
|
||||
);
|
||||
private boolean collectionTypeHasCompatibleConstructor(Type sourceType, Type targetType) {
|
||||
// note (issue #127): actually this should check for the presence of a matching constructor, with help of
|
||||
// Types#asMemberOf(); but this method seems to not work correctly in the Eclipse implementation, so instead we
|
||||
// just check whether the target type is parameterized in a way that it implicitly should have a constructor
|
||||
// which accepts the source type
|
||||
|
||||
for ( ExecutableElement constructor : targetTypeConstructors ) {
|
||||
if ( constructor.getParameters().size() != 1 ) {
|
||||
continue;
|
||||
TypeMirror sourceElementType = sourceType.getTypeParameters().isEmpty() ?
|
||||
typeFactory.getType( Object.class ).getTypeMirror() :
|
||||
sourceType.getTypeParameters().get( 0 ).getTypeMirror();
|
||||
|
||||
TypeMirror targetElementType = targetType.getTypeParameters().isEmpty() ?
|
||||
typeFactory.getType( Object.class ).getTypeMirror() :
|
||||
targetType.getTypeParameters().get( 0 ).getTypeMirror();
|
||||
|
||||
return typeUtils.isAssignable( sourceElementType, targetElementType );
|
||||
}
|
||||
|
||||
//get the constructor resolved against the type arguments of specific target type
|
||||
ExecutableType typedConstructor = (ExecutableType) typeUtils.asMemberOf(
|
||||
(DeclaredType) targetType.getTypeMirror(), constructor
|
||||
);
|
||||
/**
|
||||
* Whether the given target type has a single-argument constructor which accepts the given source type.
|
||||
*
|
||||
* @param sourceType the source type
|
||||
* @param targetType the target type
|
||||
*
|
||||
* @return {@code true} if the target type has a constructor accepting the given source type, {@code false}
|
||||
* otherwise.
|
||||
*/
|
||||
private boolean mapTypeHasCompatibleConstructor(Type sourceType, Type targetType) {
|
||||
// note (issue #127): actually this should check for the presence of a matching constructor, with help of
|
||||
// Types#asMemberOf(); but this method seems to not work correctly in the Eclipse implementation, so instead we
|
||||
// just check whether the target type is parameterized in a way that it implicitly should have a constructor
|
||||
// which accepts the source type
|
||||
|
||||
if ( typeUtils.isAssignable(
|
||||
sourceType.getTypeMirror(),
|
||||
typedConstructor.getParameterTypes().iterator().next()
|
||||
) ) {
|
||||
return true;
|
||||
TypeMirror sourceKeyType = null;
|
||||
TypeMirror targetKeyType = null;
|
||||
TypeMirror sourceValueType = null;
|
||||
TypeMirror targetValueType = null;
|
||||
|
||||
if ( sourceType.getTypeParameters().isEmpty() ) {
|
||||
sourceKeyType = typeFactory.getType( Object.class ).getTypeMirror();
|
||||
sourceValueType = typeFactory.getType( Object.class ).getTypeMirror();
|
||||
}
|
||||
else {
|
||||
sourceKeyType = sourceType.getTypeParameters().get( 0 ).getTypeMirror();
|
||||
sourceValueType = sourceType.getTypeParameters().get( 1 ).getTypeMirror();
|
||||
}
|
||||
|
||||
return false;
|
||||
if ( targetType.getTypeParameters().isEmpty() ) {
|
||||
targetKeyType = typeFactory.getType( Object.class ).getTypeMirror();
|
||||
targetValueType = typeFactory.getType( Object.class ).getTypeMirror();
|
||||
}
|
||||
else {
|
||||
targetKeyType = targetType.getTypeParameters().get( 0 ).getTypeMirror();
|
||||
targetValueType = targetType.getTypeParameters().get( 1 ).getTypeMirror();
|
||||
}
|
||||
|
||||
return typeUtils.isAssignable( sourceKeyType, targetKeyType ) &&
|
||||
typeUtils.isAssignable( sourceValueType, targetValueType );
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user