Чому відсутність анотацій не викликає ClassNotFoundException під час виконання?


91

Розглянемо такий код:

A.java:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@interface A{}

C.java:

import java.util.*;

@A public class C {
        public static void main(String[] args){
                System.out.println(Arrays.toString(C.class.getAnnotations()));
        }
}

Компіляція та запуск робіт, як очікувалося:

$ javac *.java
$ java -cp . C
[@A()]

Але тоді розгляньте це:

$ rm A.class
$ java -cp . C
[]

Я би очікував, що це кине ClassNotFoundException, оскільки @Aвідсутній. Але натомість він мовчки скидає анотацію.

Ця поведінка де-небудь задокументована в JLS, чи це химерність JVM Sun? Яке обґрунтування цього?

Це здається зручним для таких речей, як javax.annotation.Nonnull(що, здається, все одно мало бути @Retention(CLASS)), але для багатьох інших анотацій здається, що це може спричинити різні погані речі під час виконання.

Відповіді:


90

У попередніх загальнодоступних чернетках для JSR-175 (анотації) обговорювалося, чи компілятор та час виконання повинні ігнорувати невідомі анотації, щоб забезпечити більш вільне зв’язок між використанням та оголошенням анотацій. Конкретним прикладом стало використання анотацій сервера EJB для керування конфігурацією розгортання. Якщо той самий компонент повинен бути розгорнутий на іншому сервері додатків, було б зручно, якби час виконання просто ігнорував невідомі анотації, замість того, щоб викликати NoClassDefFoundError.

Навіть якщо формулювання трохи розпливчасте, я припускаю, що поведінка, яку ви бачите, зазначена в JLS 13.5.7: "... видалення анотацій не впливає на правильну зв'язок двійкових подань програм на мові програмування Java . " Я трактую це так, ніби анотації видаляються (недоступні під час виконання), програма все одно повинна посилатись і запускатись, і це означає, що невідомі анотації просто ігноруються при доступі через відображення.

Перший випуск Sun's JDK 5 не реалізував це правильно, але це було виправлено в 1.5.0_06. Ви можете знайти відповідну помилку 6322301 у базі даних про помилки, але вона не вказує на будь-які специфікації, за винятком твердження, що "відповідно до специфікації JSR-175 невідомі анотації повинні ігноруватися getAnnotations".


35

Цитування JLS:

9.6.1.2 Анотації збереження можуть бути присутніми лише у вихідному коді, або вони можуть бути присутніми у двійковій формі класу чи інтерфейсу. Анотація, яка присутня у двійковому файлі, може бути або не бути доступною під час виконання через відбивні бібліотеки платформи Java.

Анотація типу анотації. Ретенція використовується для вибору серед перерахованих вище можливостей. Якщо анотація a відповідає типу T, а T має (мета-) анотацію m, яка відповідає анотації.

  • Якщо m має елемент, значенням якого є анотація.RetentionPolicy.SOURCE, тоді компілятор Java повинен переконатися, що a не присутній у двійковому поданні класу або інтерфейсу, в якому з'являється a.
  • Якщо m має елемент, значенням якого є annotation.RetentionPolicy.CLASS або annotation.RetentionPolicy.RUNTIME, компілятор Java повинен переконатися, що a представлено у двійковому поданні класу або інтерфейсу, в якому з'являється a, якщо m не коментує локальну декларацію змінної . Анотація до оголошення локальної змінної ніколи не зберігається у двійковому поданні.

Якщо T не має (мета-) анотації m, що відповідає annotation.Retention, тоді компілятор Java повинен ставитися до T так, ніби вона має таку мета-анотацію m з елементом, значенням якого є annotation.RetentionPolicy.CLASS.

Отже, RetentionPolicy.RUNTIME гарантує, що анотація компілюється в двійковий файл, але анотація, присутня в двійковій програмі, не повинна бути доступною під час виконання


9

якщо у вас насправді є код, який читає @A і щось з ним робить, код має залежність від класу A, і він викине ClassNotFoundException.

якщо ні, тобто жоден код конкретно не дбає про @A, то можна сперечатися, що @A насправді не має значення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.