Что такое retention policy аннотаций и для чего она нужна
Что проверяют
Понимаете ли вы, что аннотация это метаданные, которые могут не дожить до запуска программы. Сразу за этим идёт практический вопрос, почему самописная аннотация не видна через рефлексию и на чём вообще держатся Spring и Hibernate.
Как отвечать
@Retention задаёт стадию, до которой аннотация доживает, и значений ровно три.
SOURCE: видна только компилятору и обработчикам аннотаций, в class-файл не попадает. Так живут@Override,@SuppressWarningsи аннотации кодогенераторов.CLASS: попадает в байт-код, но виртуальная машина её не загружает, рефлексией не достать. Это значение по умолчанию, если@Retentionне написан вовсе.RUNTIME: лежит в class-файле и читается рефлексией. На этом построены внедрение зависимостей, маппинг сущностей, сериализация, тестовые фреймворки.
Дальше объясните выбор. Аннотации, по которым код генерируется на компиляции, обходятся SOURCE. Аннотации, которые фреймворк читает во время работы приложения, требуют RUNTIME. CLASS нужна инструментам, разбирающим байт-код без загрузки классов: статические анализаторы, трансформеры, проверки на сборке.
Рядом стоит назвать соседей по объявлению: @Target ограничивает места применения, @Inherited задаёт наследование подклассами, @Repeatable разрешает вешать несколько штук, @Documented выносит аннотацию в документацию.
Где спотыкаются
Объявляют свою аннотацию без @Retention, а потом долго ищут, почему getAnnotation возвращает null. Умолчание здесь не RUNTIME, и ни компилятор, ни среда об этом не предупредят.
Считают, что RUNTIME сама по себе замедляет приложение. Дорога не стадия хранения, а рефлексия при разборе, и фреймворки читают метаданные один раз на старте, после чего кэшируют результат.
Ждут от @Inherited большего, чем она умеет. Наследование работает только для аннотаций на классах и только по цепочке наследования классов: ни интерфейсы, ни переопределённые методы её не подхватят.