2009-06-30 11 views
6

Piszę niektóre narzędzia do naszego systemu kompilacji, aby wymusić pewne ścisłe konwencje wywoływania metod należących do klas zawierających określone adnotacje.Odkryj klasę wywołania metody w procesorze adnotacji dla java

Używam API Compiler drzewo ...

Co zastanawiam się podczas przechodzenia przez „drzewa”, jak można powiedzieć, typ klasy/interfejsu dla MethodInvocation.

mi instacji TreePathScanner z:

@Override 
public Object visitMethodInvocation(MethodInvocationTree node, Trees trees) { 

} 

Mam nadzieję, że jest tam sposób powiadomić typ klasy (lub Interface), który próbujesz wywołać metodę na. Czy podchodzę do tego w niewłaściwy sposób? Dzięki za wszelkie pomysły ...

Odpowiedz

8

Jest kilka problemów tutaj. Możesz być zainteresowany znając typ Java odbiornika wywołania metody lub po prostu wiedząc, że klasa w tej metodzie jest wywoływana. Informacje Java są bardziej informacyjne, ponieważ dają także ogólne typy, np. List<String> , podczas gdy elementy zapewniłyby Tobie tylko klasę, np. List<E>.

Pierwsze Element

Aby uzyskać element klasy metoda wywoływana jest, można zrobić następujące:


    MethodInvocationTree node = ...; 
    Element method = 
     TreeInfo.symbol((JCTree)node.getMethodSelect()); 
    TypeElement invokedClass = (TypeElement)method.getEnclosingElement(); 

przypadkach róg:

1. invokedClass może być nadklasą typu odbiornika. Tak działa fragment na new ArrayList<String>.equals(null) wróci AbstractList zamiast ArrayList, ponieważ równych() jest realizowany w AbstractList nie ArrayList.

2. Podczas obsługi wywołań tablicy, np. new int[].clone(), można uzyskać uzyskać TypeElement klasy Array.

Uzyskiwanie rzeczywisty typ

Aby uzyskać typ, nie istnieje bezpośredni sposób określania go co typ odbiornik. Istnieje pewna złożoność wywołań metod obsługi w obrębie klas wewnętrznych, w których odbiornik nie jest wyraźnie określony (np. W przeciwieństwie do OuterClass.this.toString()). Oto próbka realizacja:


    MethodInvocationTree node = ...; 
    TypeMirror receiver; 
    if (methodSel.getKind() == Tree.Kind.MEMBER_SELECT) { 
    ExpressionTree receiver = ((MemberSelectTree)methodSel).getExpression(); 
    receiverType = ((JCTree)receiver).type; 
    } else if (methodSel.getKind() == Tree.Kind.IDENTIFIER) { 
    // need to resolve implicit this, which is described in 
    // JLS3 15.12.1 and 15.9.2 

    // A bit too much work that I don't want to work on now 
    // Look at source code of 
    // Attr.visitApply(JCMethodInvocation) 
    // resolveImplicitThis(DiagnosticPosition, Env, Type) 
    } else 
    throw new AssertionError("Unexpected type: " + methodSel.getKind()); 

Uwaga:

Typ receiver musi być TypeMirror nie DeclaredType niestety. Podczas wywoływania new int[5].clone(), będzie bardziej informacyjny niż poprzedni metoda .

Uzyskanie go uruchomić

oba poprzednich metod wymagają kompilator rozpoznać typ informacji dla klas. W zwykłych okolicznościach kompilator rozwiązuje tylko typy deklaracji metod, ale nie ciał. W związku z tym opisane wcześniej metody zwrócą numer null.

Aby kompilator rozwiązać wpisz informacje, można wykonać jedną z następujących sposobów:

1. Zastosowanie AbstractTypeProcessor klasy, który właśnie został dodany do repozytorium kompilatora dla JDK 7. Sprawdź pracy na JSR 308 i ich kompilator. Podczas gdy praca dotyczy głównie typów z przypisami, może być przydatna. Kompilator pozwala na użycie dostarczonego klasę w zacofanym sposób zgodny z Java 5.

Takie podejście pozwala na pisanie procesory, które się powoływać tylko jak aktualnych procesorów.

2. Zamiast tego należy użyć JavacTask i zadzwonić pod numer JavacTask.analyze(). Spójrz na główną metodą pod numerem this javac test, aby zobaczyć, w jaki sposób można wywołać swojego gościa na zajęciach.

Takie podejście sprawia, że ​​procesor wygląda bardziej jak narzędzie analityczne niż wtyczka do kompilatora, ponieważ trzeba go wywoływać bezpośrednio, a nie jako zwykły proces.

+0

Dziękuję za odpowiedź. Jednak linia: Metoda elementu = TreeInfo.symbol ((JCTree) node.getMethodSelect()); zwraca dla mnie wartość null. \t TypeMirror m = trees.getTypeMirror (ścieżka); zwraca także wartość null, podobnie jak \t TypeElement e = (TypeElement) trees.getElement (ścieżka); Czy popełniam błąd debiutanta i zapominając o zainicjowaniu czegoś lub wywołaniu/przesłonięciu niewłaściwej metody lub podklasowaniu czegoś złego? Jeszcze raz dziękuję za pomoc ... – runT1ME

+0

Właśnie zaktualizowałem wpis, aby wyjaśnić, dlaczego metody zwracają wartość null i jak adresować ten numer: – notnoop

+0

, AbstractTypeProcessor nie jest już dostępny w kompilacjach JDK 7, ponieważ obsługa JSR 308 została usunięta. –

Powiązane problemy