Types isAssignable et isSubtype incompréhension

En écrivant un processeur d’annotation à l’aide de l’API Java 6, j’ai découvert qu’il était nécessaire de gérer toutes les cartes de manière particulière, mais je ne comprends clairement pas ce que l’API est censée faire ou comment l’invoquer. Voici le code qui me rend malheureux:

import javax.lang.model.element.Element; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; import javax.annotation.processing.ProcessingEnvironment; ... public Ssortingng doThing(Element el, ProcessingEnvironment processingEnv) { // Utilities from the ProcessingEnvironment Types typeUtils = processingEnv.getTypeUtils(); Elements elementUtils = processingEnv.getElementUtils(); // The type of the element I'm handling TypeMirror elType = el.asType(); // Compare the element's type to Map TypeMirror mapType = elementUtils.getTypeElement("java.util.Map").asType(); System.out.println(elType + " > " + mapType + " = " + typeUtils.isSubtype(elType, mapType)); System.out.println(mapType + " > " + elType + " = " + typeUtils.isSubtype(mapType, elType)); System.out.println(elType + " > " + mapType + " = " + typeUtils.isAssignable(elType, mapType)); System.out.println(mapType + " > " + elType + " = " + typeUtils.isAssignable(mapType, elType)); // Compare the element's type to HashMap TypeMirror hashmapType = elementUtils.getTypeElement("java.util.HashMap").asType(); System.out.println(elType + " > " + hashmapType + " = " + typeUtils.isSubtype(elType, hashmapType)); System.out.println(hashmapType + " > " + elType + " = " + typeUtils.isSubtype(hashmapType, elType)); System.out.println(elType + " > " + hashmapType + " = " + typeUtils.isAssignable(elType, hashmapType)); System.out.println(hashmapType + " > " + elType + " = " + typeUtils.isAssignable(hashmapType, elType)); // Compare the element's type to Object TypeMirror objectType = elementUtils.getTypeElement("java.lang.Object").asType(); System.out.println(elType + " > " + objectType + " = " + typeUtils.isSubtype(elType, objectType)); System.out.println(objectType + " > " + elType + " = " + typeUtils.isSubtype(objectType, elType)); System.out.println(elType + " > " + objectType + " = " + typeUtils.isAssignable(elType, objectType)); System.out.println(objectType + " > " + elType + " = " + typeUtils.isAssignable(objectType, elType)); } 

Compte tenu de cela, voici le résultat:

 java.util.HashMap > java.util.Map = false java.util.Map > java.util.HashMap = false java.util.HashMap > java.util.Map = false java.util.Map > java.util.HashMap = false java.util.HashMap > java.util.HashMap = true java.util.HashMap > java.util.HashMap = true java.util.HashMap > java.util.HashMap = true java.util.HashMap > java.util.HashMap = true java.util.HashMap > java.lang.Object = true java.lang.Object > java.util.HashMap = false java.util.HashMap > java.lang.Object = true java.lang.Object > java.util.HashMap = false 

Cela me semble tout à fait logique, sauf pour le premier bloc dans lequel un élément HashMap serait assignable à Map et dans lequel HashMap serait un sous-type de Map.

Qu’est-ce que j’oublie ici?

Je soupçonne que c’est à cause des variables de type. HashMap est assignable à Map mais sans l’instanciation concrète des variables de type, vous ne pouvez pas être sûr qu’un HashMap arbitraire est assignable à Map .

Si vous instanciez les variables avec des caractères génériques, vous devriez obtenir le résultat attendu

 DeclaredType wildcardMap = typeUtils.getDeclaredType( elementUtils.getTypeElement("java.util.Map"), typeUtils.getWildcardType(null, null), typeUtils.getWildcardType(null, null)); 

Cela vous donnera le type miroir de Map , HashMap toutes les instanciations HashMap sont assignables.

Mise à jour (mars 2016) : D’après un commentaire de @ user1643723, il semble exister une fonction de bibliothèque types.erasure(TypeMirror) dont je n’avais pas connaissance en 2012.


Sur la base de la réponse de Ian , j’utilise maintenant la méthode suivante pour faire correspondre les types de base tels que ceux décrits dans Map pour la carte

 TypeElement COLLECTION = elementUtils.getTypeElement("java.util.Collection"); TypeElement MAP = elementUtils.getTypeElement("java.util.Map"); TypeElement VOID = elementUtils.getTypeElement("java.lang.Void"); WildcardType WILDCARD_TYPE_NULL = typeUtils.getWildcardType(null, null); Map cachedParentTypes = new HashMap(); ... public static boolean isA(TypeMirror type, TypeElement typeElement) { // Have we used this type before? DeclaredType parentType = cachedParentTypes.get(typeElement.getQualifiedName().toSsortingng()); if (parentType == null) { // How many generic type parameters does this typeElement require? int genericsCount = typeElement.getTypeParameters().size(); // Fill the right number of types with nulls TypeMirror[] types = new TypeMirror[genericsCount]; for (int i = 0; i < genericsCount; i++) { types[i] = WILDCARD_TYPE_NULL; } // Locate the correct DeclaredType to match with the type parentType = typeUtils.getDeclaredType(typeElement, types); // Remember this DeclaredType cachedParentTypes.put(typeElement.getQualifiedName().toString(), parentType); } // Is the given type able to be assigned as the typeElement? return typeUtils.isAssignable(type, parentType); } 

que j'invoque comme

 if (isA(elType, VOID)) { isVoid = true; } else if (isA(elType, COLLECTION) || elType.getKind() == TypeKind.ARRAY) { isCollectionOrArray = true; } else if (isA(elType, MAP)){ isMap = true; }