Подтвердить что ты не робот

Аннотации TYPE_USE теряются, когда тип вложен, общий интерфейс

Похоже, что аннотации TYPE_USE недоступны через отражение, когда аннотированный тип является вложенным, общим интерфейсом.

Обратите внимание на следующий пример:

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<String, String> map;
  @SomeTypeAnnotation Entry<String, String> entry;

  public static @SomeTypeAnnotation Entry<String, String> someMethod(
      @SomeTypeAnnotation Map<String, String> map,
      @SomeTypeAnnotation Entry<String, String> entry) {
    return null;
  }

  public static void main(String[] args) throws Exception {
    Class<LostAnnotation> 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(String title, AnnotatedType type) {
    System.out.printf("%s: %s%n", title, Arrays.asList(type.getAnnotations()));
  }
}

ожидаемый вывод вышеприведенного кода

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

Однако фактический вывод приведенного выше кода

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

Аннотации корректно извлекаются из каждого использования интерфейса Map. Однако при каждом использовании интерфейса Entry, будь то поле, тип или параметр возврата, аннотация теряется. Единственное объяснение, которое у меня есть для этого, заключается в том, что интерфейс Entry вложен внутри интерфейса Map.

Я запустил приведенный выше пример на новейшем оракуле JDK (8u121) на win64. Я делаю что-то неправильно или это может быть ошибка?

Моя аннотация вложена для удобочитаемости. Создание интерфейса верхнего уровня ничего не меняет.

4b9b3361

Ответ 1

Это уже отмечено в SO: Почему аннотация для аргумента generic type не отображается для вложенного типа?

Ответ - ошибка была отправлена, но в более низком приоритете, поскольку эти случаи часто не отображаются.

Тем не менее, вы можете использовать ByteBuddy для анализа байт-кода и получения аннотированного типа.

ASM тоже работает, по моему опыту, и я подозреваю, что любой байт-код-парсер будет работать вокруг этой ошибки.

Ответ 2

Я не знаю, считаюсь ли я надежным источником (определенно, не официальным), но IMO - это ошибка или, по крайней мере, недостаток (не полностью реализованный) в JDK.

Вы ничего не делаете неправильно - или мы оба ошибаемся, что по-прежнему возможно.

Как сказал Бертран Рассел:

Тот факт, что мнение широко распространено, не является доказательством того, что оно не является абсолютно абсурдным.

; -)