mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
Issue #79 Fixing suggestions
This commit is contained in:
parent
b249c2ced1
commit
560855004b
@ -25,17 +25,13 @@ import javax.lang.model.element.TypeParameterElement;
|
|||||||
import javax.lang.model.element.VariableElement;
|
import javax.lang.model.element.VariableElement;
|
||||||
import javax.lang.model.type.ArrayType;
|
import javax.lang.model.type.ArrayType;
|
||||||
import javax.lang.model.type.DeclaredType;
|
import javax.lang.model.type.DeclaredType;
|
||||||
import javax.lang.model.type.ErrorType;
|
|
||||||
import javax.lang.model.type.ExecutableType;
|
|
||||||
import javax.lang.model.type.NoType;
|
|
||||||
import javax.lang.model.type.NullType;
|
|
||||||
import javax.lang.model.type.PrimitiveType;
|
import javax.lang.model.type.PrimitiveType;
|
||||||
import javax.lang.model.type.TypeKind;
|
import javax.lang.model.type.TypeKind;
|
||||||
import static javax.lang.model.type.TypeKind.DECLARED;
|
import static javax.lang.model.type.TypeKind.DECLARED;
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
import javax.lang.model.type.TypeVariable;
|
import javax.lang.model.type.TypeVariable;
|
||||||
import javax.lang.model.type.WildcardType;
|
import javax.lang.model.type.WildcardType;
|
||||||
import javax.lang.model.util.AbstractTypeVisitor6;
|
import javax.lang.model.util.SimpleTypeVisitor6;
|
||||||
import javax.lang.model.util.Types;
|
import javax.lang.model.util.Types;
|
||||||
import org.mapstruct.ap.model.Type;
|
import org.mapstruct.ap.model.Type;
|
||||||
import org.mapstruct.ap.model.source.Method;
|
import org.mapstruct.ap.model.source.Method;
|
||||||
@ -93,7 +89,8 @@ public class MethodMatcher {
|
|||||||
if ( candidateParameters.size() == parameters.length ) {
|
if ( candidateParameters.size() == parameters.length ) {
|
||||||
for ( int i = 0; i < parameters.length; i++ ) {
|
for ( int i = 0; i < parameters.length; i++ ) {
|
||||||
TypeMatcher parameterMatcher = new TypeMatcher();
|
TypeMatcher parameterMatcher = new TypeMatcher();
|
||||||
parameterMatcher.visit( candidateParameters.get( i ).asType(), parameters[i].getTypeMirror() );
|
typesMatch = parameterMatcher.visit( candidateParameters.get( i ).asType(),
|
||||||
|
parameters[i].getTypeMirror() );
|
||||||
if ( !typesMatch ) {
|
if ( !typesMatch ) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -107,7 +104,7 @@ public class MethodMatcher {
|
|||||||
if ( typesMatch ) {
|
if ( typesMatch ) {
|
||||||
TypeMirror candidateReturnType = candidateMethod.getExecutable().getReturnType();
|
TypeMirror candidateReturnType = candidateMethod.getExecutable().getReturnType();
|
||||||
TypeMatcher returnTypeMatcher = new TypeMatcher();
|
TypeMatcher returnTypeMatcher = new TypeMatcher();
|
||||||
returnTypeMatcher.visit( candidateReturnType, returnType.getTypeMirror() );
|
typesMatch = returnTypeMatcher.visit( candidateReturnType, returnType.getTypeMirror() );
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if all type parameters are indeed mapped
|
// check if all type parameters are indeed mapped
|
||||||
@ -126,85 +123,75 @@ public class MethodMatcher {
|
|||||||
return typesMatch;
|
return typesMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TypeMatcher extends AbstractTypeVisitor6<TypeMirror, TypeMirror> {
|
public class TypeMatcher extends SimpleTypeVisitor6<Boolean, TypeMirror> {
|
||||||
|
|
||||||
@Override
|
public TypeMatcher() {
|
||||||
public TypeMirror visitPrimitive(PrimitiveType t, TypeMirror p) {
|
super( Boolean.TRUE ); // default value
|
||||||
if ( !typeUtils.isSameType( t, p ) ) {
|
|
||||||
typesMatch = false;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TypeMirror visitNull(NullType t, TypeMirror p) {
|
public Boolean visitPrimitive(PrimitiveType t, TypeMirror p) {
|
||||||
// not interesting
|
return typeUtils.isSameType( t, p );
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TypeMirror visitArray(ArrayType t, TypeMirror p) {
|
public Boolean visitArray(ArrayType t, TypeMirror p) {
|
||||||
|
|
||||||
if ( p instanceof ArrayType ) {
|
if ( p.getKind().equals( TypeKind.ARRAY) ) {
|
||||||
t.getComponentType().accept( this, ( (ArrayType) p ).getComponentType() );
|
t.getComponentType().accept( this, ( (ArrayType) p ).getComponentType() );
|
||||||
|
return Boolean.TRUE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
typesMatch = false;
|
return Boolean.FALSE;
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TypeMirror visitDeclared(DeclaredType t, TypeMirror p) {
|
public Boolean visitDeclared(DeclaredType t, TypeMirror p) {
|
||||||
// its a match when: 1) same kind of type, name is equals, nr of type args are the same
|
// its a match when: 1) same kind of type, name is equals, nr of type args are the same
|
||||||
// (type args are checked later).
|
// (type args are checked later).
|
||||||
if ( p instanceof DeclaredType ) {
|
if ( p.getKind().equals( TypeKind.DECLARED ) ) {
|
||||||
DeclaredType t1 = (DeclaredType) p;
|
DeclaredType t1 = (DeclaredType) p;
|
||||||
if ( t.asElement().getSimpleName().equals( t1.asElement().getSimpleName() )
|
if ( t.asElement().getSimpleName().equals( t1.asElement().getSimpleName() )
|
||||||
&& t.getTypeArguments().size() == t1.getTypeArguments().size() ) {
|
&& t.getTypeArguments().size() == t1.getTypeArguments().size() ) {
|
||||||
for ( int i = 0; i < t.getTypeArguments().size(); i++ ) {
|
for ( int i = 0; i < t.getTypeArguments().size(); i++ ) {
|
||||||
t.getTypeArguments().get( i ).accept( this, t1.getTypeArguments().get( i ) );
|
if (!t.getTypeArguments().get( i ).accept( this, t1.getTypeArguments().get( i ) ))
|
||||||
|
{
|
||||||
|
return Boolean.FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Boolean.TRUE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Boolean.FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
typesMatch = false;
|
return Boolean.FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
typesMatch = false;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TypeMirror visitError(ErrorType t, TypeMirror p) {
|
public Boolean visitTypeVariable(TypeVariable t, TypeMirror p) {
|
||||||
// not interesting
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeMirror visitTypeVariable(TypeVariable t, TypeMirror p) {
|
|
||||||
if ( genericTypesMap.containsKey( t ) ) {
|
if ( genericTypesMap.containsKey( t ) ) {
|
||||||
// when already found, the same mapping should apply
|
// when already found, the same mapping should apply
|
||||||
TypeMirror p1 = genericTypesMap.get( t );
|
TypeMirror p1 = genericTypesMap.get( t );
|
||||||
if ( !typeUtils.isSameType( p, p1 ) ) {
|
return typeUtils.isSameType( p, p1 );
|
||||||
typesMatch = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// check if types are in bound
|
// check if types are in bound
|
||||||
if ( typeUtils.isSubtype( t.getLowerBound(), p ) && typeUtils.isSubtype( p, t.getUpperBound() ) ) {
|
if ( typeUtils.isSubtype( t.getLowerBound(), p ) && typeUtils.isSubtype( p, t.getUpperBound() ) ) {
|
||||||
genericTypesMap.put( t, p );
|
genericTypesMap.put( t, p );
|
||||||
|
return Boolean.TRUE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
typesMatch = false;
|
return Boolean.FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TypeMirror visitWildcard(WildcardType t, TypeMirror p) {
|
public Boolean visitWildcard(WildcardType t, TypeMirror p) {
|
||||||
|
|
||||||
// check extends bound
|
// check extends bound
|
||||||
TypeMirror extendsBound = t.getExtendsBound();
|
TypeMirror extendsBound = t.getExtendsBound();
|
||||||
@ -212,24 +199,18 @@ public class MethodMatcher {
|
|||||||
switch ( extendsBound.getKind() ) {
|
switch ( extendsBound.getKind() ) {
|
||||||
case DECLARED:
|
case DECLARED:
|
||||||
// for example method: String method(? extends String)
|
// for example method: String method(? extends String)
|
||||||
if ( !typeUtils.isSubtype( p, extendsBound ) ) {
|
|
||||||
// isSubType checks range [subtype, type], e.g. isSubtype [Object, String]==true
|
// isSubType checks range [subtype, type], e.g. isSubtype [Object, String]==true
|
||||||
typesMatch = false;
|
return typeUtils.isSubtype( p, extendsBound );
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TYPEVAR:
|
case TYPEVAR:
|
||||||
// for exampe method: <T extends String & Serializable> T method(? extends T)
|
// for exampe method: <T extends String & Serializable> T method(? extends T)
|
||||||
// this can be done the directly by checking: ? extends String & Serializable
|
// this can be done the directly by checking: ? extends String & Serializable
|
||||||
if ( !isWithinBounds( p, getTypeParamFromCandite( extendsBound ) ) ) {
|
|
||||||
// this checks the part? <T extends String & Serializable>
|
// this checks the part? <T extends String & Serializable>
|
||||||
typesMatch = false;
|
return isWithinBounds( p, getTypeParamFromCandite( extendsBound ) );
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// does this situation occur?
|
// does this situation occur?
|
||||||
typesMatch = false;
|
return Boolean.FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,12 +220,9 @@ public class MethodMatcher {
|
|||||||
switch ( superBound.getKind() ) {
|
switch ( superBound.getKind() ) {
|
||||||
case DECLARED:
|
case DECLARED:
|
||||||
// for example method: String method(? super String)
|
// for example method: String method(? super String)
|
||||||
if ( !( typeUtils.isSubtype( superBound, p ) || typeUtils.isSameType( p, superBound ) ) ) {
|
|
||||||
// to check super type, we can simply reverse the argument, but that would initially yield
|
// to check super type, we can simply reverse the argument, but that would initially yield
|
||||||
// a result: <type, superType] (so type not included) so we need to check sameType also.
|
// a result: <type, superType] (so type not included) so we need to check sameType also.
|
||||||
typesMatch = false;
|
return ( typeUtils.isSubtype( superBound, p ) || typeUtils.isSameType( p, superBound ) );
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TYPEVAR:
|
case TYPEVAR:
|
||||||
|
|
||||||
@ -252,40 +230,27 @@ public class MethodMatcher {
|
|||||||
// for exampe method: <T extends String & Serializable> T method(? super T)
|
// for exampe method: <T extends String & Serializable> T method(? super T)
|
||||||
if ( !isWithinBounds( p, typeParameter ) ) {
|
if ( !isWithinBounds( p, typeParameter ) ) {
|
||||||
// this checks the part? <T extends String & Serializable>
|
// this checks the part? <T extends String & Serializable>
|
||||||
typesMatch = false;
|
return Boolean.FALSE;
|
||||||
}
|
}
|
||||||
// now, it becoms a bit more hairy. We have the relation (? super T). From T we know that
|
// now, it becoms a bit more hairy. We have the relation (? super T). From T we know that
|
||||||
// it is a subclass of String & Serializable. However, The Java Language Secification,
|
// it is a subclass of String & Serializable. However, The Java Language Secification,
|
||||||
// Chapter 4.4, states that a bound is either: 'A type variable-', 'A class-' or 'An
|
// Chapter 4.4, states that a bound is either: 'A type variable-', 'A class-' or 'An
|
||||||
// interface-' type followed by further interface types. So we must compare with the first
|
// interface-' type followed by further interface types. So we must compare with the first
|
||||||
// argument in the Expression String & Serializable & ..., so, in this case String.
|
// argument in the Expression String & Serializable & ..., so, in this case String.
|
||||||
TypeMirror superBoundAsDeclared = typeParameter.getBounds().get( 0 );
|
|
||||||
if ( !( typeUtils.isSubtype( superBoundAsDeclared, p ) ||
|
|
||||||
typeUtils.isSameType( p, superBoundAsDeclared ) ) ) {
|
|
||||||
// to check super type, we can simply reverse the argument, but that would initially yield
|
// to check super type, we can simply reverse the argument, but that would initially yield
|
||||||
// a result: <type, superType] (so type not included) so we need to check sameType also.
|
// a result: <type, superType] (so type not included) so we need to check sameType also.
|
||||||
typesMatch = false;
|
TypeMirror superBoundAsDeclared = typeParameter.getBounds().get( 0 );
|
||||||
}
|
return ( typeUtils.isSubtype( superBoundAsDeclared, p ) ||
|
||||||
break;
|
typeUtils.isSameType( p, superBoundAsDeclared ) );
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// does this situation occur?
|
// does this situation occur?
|
||||||
typesMatch = false;
|
return Boolean.FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return Boolean.TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeMirror visitExecutable(ExecutableType t, TypeMirror p) {
|
|
||||||
// not interesting
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypeMirror visitNoType(NoType t, TypeMirror p) {
|
|
||||||
// not interesting
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user