2016-05-31 5 views
2

У меня есть интерфейс вроде этого:Как получить квалифицированное имя класса родового типа в обработке аннотаций?

interface MyInterface<V>{ 

} 

и все мои аннотированных классов с @MyAnnotation реализовать этот интерфейс по-разному, например.

//first way 
Class1 implement MyInterface<SomeClass> 
//second way 
AbstractClass<V> implement MyInterface<V> 
Class2 extends AbstractClass<SomeClass> 
//third way  
ConcreteClass implement MyInterface<SomeClass> 
Class3 extends ConcreteClass 

Ну, у меня есть TypeElement S класса 1,2 и 3, и я хочу, чтобы найти полное имя типа переменной V.

Я попробовал это, но он возвращает V вместо SomeClass.

TypeElement class1 = ... 
while(reachToMyInterface){ 
for (TypeMirror m : ((DeclaredType) class1.asType()).getTypeArguments()) { 
     print(m.toString()) // prints V 
    } 
    class1 = getItsSuperClass(); 
} 

Edit: Кроме того, этот подход имеет те же проблемы:

for (Element element : roundEnv.getElementsAnnotatedWith(Haha.class)) { 
      if (element instanceof TypeElement) { 
       TypeElement te = (TypeElement) element; 
       TypeElement currentType = te; 
       while(currentType!=null){ 
       for (TypeMirror typeMirror : currentType .getInterfaces()) { 
        if (typeMirror instanceof DeclaredType) { 
         DeclaredType dclt = (DeclaredType) typeMirror; 
         for (TypeMirror argument : dclt.getTypeArguments()) { 
         print(argument); 
         } 
        } 
       } 
       currentType = getSuperClass(currentType);     
       } 
} 
private TypeElement getSuperClass(TypeElement typeElement) { 
     if (!(typeElement.getSuperclass() instanceof DeclaredType)) return null; 
     DeclaredType declaredAncestor = (DeclaredType) typeElement.getSuperclass(); 

     return (TypeElement) declaredAncestor.asElement(); 
    } 
+0

@JornVernee если 'MyInterface' имеет метод' void foo (V bar) ', то можно ли получить' MyClass'? Я все еще путаюсь со вторым способом, потому что возможно, что Class2 не переопределяет 'foo' –

+0

@ Обработка событий annornation @JornVernee происходит во время компиляции, а не во время выполнения. И ваше утверждение также неверно для времени выполнения. Типы экземпляров стираются, но ограничения типов в классах, методах и полях сохраняются. Запрос этой информации - очень продвинутый предмет. Это обсуждается здесь: https://github.com/google/guava/wiki/ReflectionExplained#typetoken –

ответ

3

Это больно, но это может быть сделано.

С этими типами:

@Retention(RUNTIME) @Target(TYPE) public @interface Haha {} 

interface MyInterface<V>{} 

@Haha public class StringImpl implements MyInterface<String> {} 

Вот аннотацию процессор, который печатает "java.lang.String" для @Haha аннотацию на StringImpl:

public class Proc extends AbstractProcessor { 
    @Override public Set<String> getSupportedAnnotationTypes() { 
     return Collections.singleton("bar.Haha"); 
    } 

    @Override public SourceVersion getSupportedSourceVersion() { 
     return SourceVersion.RELEASE_8; 
    } 

    @Override public boolean process(final Set<? extends TypeElement> annotations, 
            final RoundEnvironment roundEnv) { 
     for (Element element : roundEnv.getElementsAnnotatedWith(Haha.class)) { 
      if (element instanceof TypeElement) { 
       TypeElement te = (TypeElement) element; 
       for (TypeMirror typeMirror : te.getInterfaces()) { 
        if (typeMirror instanceof DeclaredType) { 
         DeclaredType dclt = (DeclaredType) typeMirror; 
         for (TypeMirror argument : dclt.getTypeArguments()) { 
          System.out.println(argument); 
         } 
        } 
       } 
      } 
     } 
     return false; 
    } 
} 

Как есть много испытаний и и я использовал этот тест для отладки процесса:

public class ProcTest { 
    @Test 
    public void run() { 
     String basePath = "/path/to/src/folder/"; 
     List<String> args = asList("Haha", "MyInterface", "StringImpl") 
       .stream() 
       .map(s -> basePath +"bar/" + s + ".java") 
       .collect(Collectors.toList()); 
     args.addAll(0, asList("-processor", Proc.class.getName())); 
     String[] flags = args.toArray(new String[3]); 
     ToolProvider.getSystemJavaCompiler() 
        .run(System.in, System.out, System.err, flags); 
    } 
} 

Если вы запустите это в режиме отладки, вы можете установить точку останова внутри обработчика аннотации. Это помогло мне лучше понять ситуацию.

+0

Спасибо, но как насчет второго или третьего пути? –

+1

@SaeedMasoumi Я дал вам отправную точку. Вы поймете это оттуда. –

+0

Хорошо, если я получу всех предков для каждого элемента и получаю аргументы типа их интерфейсов 'System.out.println (аргумент);' будет печатать 'V' вместо' SomeClass' –