Les annotations TYPE_USE sont perdues lorsque le type est nested, interface générique

Il semble que l’access aux annotations TYPE_USE n’est pas possible par reflection lorsque le type annoté est une interface générique nestede.

Veuillez observer l’exemple suivant:

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.AnnotatedType; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Map; import java.util.Map.Entry; public class LostAnnotation { @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE_USE) public @interface SomeTypeAnnotation { } @SomeTypeAnnotation Map map; @SomeTypeAnnotation Entry entry; public static @SomeTypeAnnotation Entry someMethod( @SomeTypeAnnotation Map map, @SomeTypeAnnotation Entry entry) { return null; } public static void main(Ssortingng[] args) throws Exception { Class clazz = LostAnnotation.class; Method method = clazz.getMethod("someMethod", Map.class, Entry.class); AnnotatedType[] types = method.getAnnotatedParameterTypes(); print("map field", clazz.getDeclaredField("map").getAnnotatedType()); print("map parameter", types[0]); print("entry field", clazz.getDeclaredField("entry").getAnnotatedType()); print("entry parameter", types[1]); print("entry return type", method.getAnnotatedReturnType()); } static void print(Ssortingng title, AnnotatedType type) { System.out.printf("%s: %s%n", title, Arrays.asList(type.getAnnotations())); } } 

Le résultat attendu du code ci-dessus est

 map field: [@LostAnnotation$SomeTypeAnnotation()] map parameter: [@LostAnnotation$SomeTypeAnnotation()] entry field: [@LostAnnotation$SomeTypeAnnotation()] entry parameter: [@LostAnnotation$SomeTypeAnnotation()] entry return type: [@LostAnnotation$SomeTypeAnnotation()] 

Cependant, la sortie réelle du code ci-dessus est

 map field: [@LostAnnotation$SomeTypeAnnotation()] map parameter: [@LostAnnotation$SomeTypeAnnotation()] entry field: [] entry parameter: [] entry return type: [] 

L’annotation est correctement extraite de chaque utilisation de l’interface Map . Toutefois, à chaque utilisation de l’interface Entry , qu’il s’agisse d’un champ, d’un type ou d’un paramètre, l’annotation est perdue. La seule explication que j’ai à cela est que l’interface Entry est nestede dans l’interface Map .

J’ai couru l’exemple ci-dessus sur le dernier oracle JDK (8u121) sur win64. Est-ce que je fais quelque chose de mal ou est-ce que cela pourrait être un bug?

Mon annotation est nestede pour plus de lisibilité. En faire une interface de haut niveau ne change rien.

Cela a déjà été repéré dans SO: Pourquoi l’annotation sur un argument de type générique n’est pas visible pour un type nested?

Answer is Bug a été soumis, mais avec une priorité inférieure car ces cas n’apparaissent pas fréquemment.

Néanmoins, vous pouvez utiliser ByteBuddy pour parsingr le bytecode et récupérer le type annoté.

D’ après mon expérience, ASM fonctionne également, et je suppose que tout parsingur de bytecode contournerait ce bogue.

Je ne sais pas si je compte comme une source crédible (certainement pas officielle), mais je pense qu’il s’agit d’un bogue ou tout au moins d’une lacune (non complètement mise en œuvre) dans le JDK.

Vous ne faites rien de mal – ou nous avons tous les deux tort, ce qui est toujours une possibilité.

Comme le disait Bertrand Russell:

Le fait qu’une opinion ait été largement partagée ne prouve en aucune manière qu’elle n’est pas totalement absurde.

😉