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.Element;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
import javax.lang.model.element.TypeElement;
|
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.TypeKind;
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
import javax.lang.model.util.ElementFilter;
|
|
||||||
import javax.lang.model.util.Elements;
|
import javax.lang.model.util.Elements;
|
||||||
import javax.lang.model.util.Types;
|
import javax.lang.model.util.Types;
|
||||||
import javax.tools.Diagnostic.Kind;
|
import javax.tools.Diagnostic.Kind;
|
||||||
@ -818,20 +815,21 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
private void reportErrorIfPropertyCanNotBeMapped(Method method, PropertyMapping property) {
|
private void reportErrorIfPropertyCanNotBeMapped(Method method, PropertyMapping property) {
|
||||||
boolean collectionOrMapTargetTypeHasCompatibleConstructor = false;
|
boolean collectionOrMapTargetTypeHasCompatibleConstructor = false;
|
||||||
|
|
||||||
if ( property.getTargetType().isCollectionType() || property.getTargetType().isMapType() ) {
|
if ( property.getSourceType().isCollectionType() && property.getTargetType().isCollectionType() ) {
|
||||||
if ( property.getTargetType().getImplementationType() != null ) {
|
collectionOrMapTargetTypeHasCompatibleConstructor = collectionTypeHasCompatibleConstructor(
|
||||||
collectionOrMapTargetTypeHasCompatibleConstructor = hasCompatibleConstructor(
|
|
||||||
property.getSourceType(),
|
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.getSourceType(),
|
||||||
property.getTargetType()
|
property.getTargetType().getImplementationType() != null ?
|
||||||
|
property.getTargetType().getImplementationType() : property.getTargetType()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ( property.getSourceType().isAssignableTo( property.getTargetType() ) ||
|
if ( property.getSourceType().isAssignableTo( property.getTargetType() ) ||
|
||||||
property.getMappingMethod() != null ||
|
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}
|
* @return {@code true} if the target type has a constructor accepting the given source type, {@code false}
|
||||||
* otherwise.
|
* otherwise.
|
||||||
*/
|
*/
|
||||||
private boolean hasCompatibleConstructor(Type sourceType, Type targetType) {
|
private boolean collectionTypeHasCompatibleConstructor(Type sourceType, Type targetType) {
|
||||||
List<ExecutableElement> targetTypeConstructors = ElementFilter.constructorsIn(
|
// note (issue #127): actually this should check for the presence of a matching constructor, with help of
|
||||||
targetType.getTypeElement()
|
// Types#asMemberOf(); but this method seems to not work correctly in the Eclipse implementation, so instead we
|
||||||
.getEnclosedElements()
|
// 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 ) {
|
TypeMirror sourceElementType = sourceType.getTypeParameters().isEmpty() ?
|
||||||
if ( constructor.getParameters().size() != 1 ) {
|
typeFactory.getType( Object.class ).getTypeMirror() :
|
||||||
continue;
|
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(
|
* Whether the given target type has a single-argument constructor which accepts the given source type.
|
||||||
(DeclaredType) targetType.getTypeMirror(), constructor
|
*
|
||||||
);
|
* @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(
|
TypeMirror sourceKeyType = null;
|
||||||
sourceType.getTypeMirror(),
|
TypeMirror targetKeyType = null;
|
||||||
typedConstructor.getParameterTypes().iterator().next()
|
TypeMirror sourceValueType = null;
|
||||||
) ) {
|
TypeMirror targetValueType = null;
|
||||||
return true;
|
|
||||||
|
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