2012-10-05 18 views
11

Java 6 API'sini kullanarak bir Annotation Processor yazarken, tüm Haritalar'ı belirli bir şekilde ele alma gereği duydum, ancak API'nın ne yapmak istediğini veya nasıl çağrılacağını açıkça yanlış anladım o. Bu ilk blok haricinde bana çok mantıklıTürlerAssignable ve isSubtype yanlış anlaşılması

java.util.HashMap<K,V> > java.util.Map<K,V> = false 
java.util.Map<K,V> > java.util.HashMap<K,V> = false 
java.util.HashMap<K,V> > java.util.Map<K,V> = false 
java.util.Map<K,V> > java.util.HashMap<K,V> = false 

java.util.HashMap<K,V> > java.util.HashMap<K,V> = true 
java.util.HashMap<K,V> > java.util.HashMap<K,V> = true 
java.util.HashMap<K,V> > java.util.HashMap<K,V> = true 
java.util.HashMap<K,V> > java.util.HashMap<K,V> = true 

java.util.HashMap<K,V> > java.lang.Object = true 
java.lang.Object > java.util.HashMap<K,V> = false 
java.util.HashMap<K,V> > java.lang.Object = true 
java.lang.Object > java.util.HashMap<K,V> = false 

Ben beklediğiniz: Burada bunun çıkışı var, o

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 String 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)); 
} 

Verilen: Burada beni mutsuz yapıyor kod HashMap öğesinin Harita'ya atanması ve HashMap'in Harita'nın bir alt türü olmasını beklerim.

Burada nelerin eksik?

cevap

9

Bunun nedeni, tür değişkenleri olduğundan şüpheleniyorum. HashMap<String, String>, Map<String, String>'a atanabilir, ancak tür değişkenlerinin somut örneği olmadan, HashMap<A,B>'un rasgele bir şekilde Map<X,Y>'a atanabileceğinden emin olamazsınız. Eğer wildcard ile değişkenleri örneğini ise

o zaman tüm HashMap örneklemi göre atanabilir Map<?,?> için size tip ayna verecektir

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

Bu beklemek sonuç almak gerekir.

+0

Biliyorsunuz gibi çağırmak

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<String,DeclaredType> cachedParentTypes = new HashMap<String, DeclaredType>(); ... public static boolean isA(TypeMirror type, TypeElement typeElement) { // Have we used this type before? DeclaredType parentType = cachedParentTypes.get(typeElement.getQualifiedName().toString()); 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); } 

, bunu düşündüm ve türleri maç olacağını eşleştirilir jenerik harflerle beri düşündüm, ama sanırım değil. Teşekkürler! – Patrick

+1

Bütün bu yaklaşım ve @Patrick'in onun uygulaması çok karmaşık. Sadece 'types.isAssignable (tür, types.erasure (baseGenerifiedType))' işlevini kullanın (ör. HashMap 'yerine raw 'HashMap' türünün atanabilir olup olmadığını kontrol edin) – user1643723

2

Güncellemesi (2016 Mart): @ user1643723 tarafından bir açıklama dayanarak, ben Ian's Answer dayanarak içinde 2012.


farkında değildi bir types.erasure(TypeMirror) kütüphane işlevi var gibi görünmektedir ben Şimdi, Haritadaki soru için tarif ettiğim gibi temel türleri eşleştirmek için aşağıdaki yöntemi kullanıyorum. Ben

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