2010-08-25 4 views
76

Рассмотрим следующий код:Почему отсутствующая аннотация вызывает исключение ClassNotFoundException во время выполнения?

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)), но для многих других аннотаций кажется, что это может вызвать различные плохие вещи во время выполнения.

ответ

81

В предыдущих публичных проектах для JSR-175 (аннотации) обсуждалось, следует ли игнорировать неизвестные аннотации компилятора и среды выполнения, чтобы обеспечить более слабую связь между использованием и объявлением аннотаций. Конкретным примером является использование аннотаций конкретных серверов приложений в EJB для управления конфигурацией развертывания. Если один и тот же компонент должен быть развернут на другом сервере приложений, было бы удобно, если бы среда выполнения просто игнорировала неизвестные аннотации, а не поднимала NoClassDefFoundError.

Даже если формулировка немного расплывчата, я предполагаю, что поведение, которое вы видите, указано в JLS 13.5.7: «... удаление аннотаций не влияет на правильную привязку двоичных представлений программ в язык программирования Java ». Я интерпретирую это так, как будто аннотации удаляются (недоступны во время выполнения), программа все равно должна связываться и запускаться, и это означает, что неизвестные аннотации просто игнорируются при доступе через отражение.

Первый выпуск JDK 5 от Sun не реализовал это правильно, но он был исправлен в 1.5.0_06. Вы можете найти соответствующую ошибку 6322301 в базе данных об ошибках, но она не указывает на какие-либо спецификации, за исключением того, что «согласно спецификации спецификации JSR-175, неизвестные аннотации должны игнорироваться getAnnotations».

32

Цитируя JLS:

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

Аннотации типа аннотация. Рекомендуется использовать среди вышеуказанных возможностей. Если аннотаций а соответствует типу T, и Т имеет (мета) аннотаций м, что соответствует annotation.Retention, то:

  • Если т есть элемент, значение которого annotation.RetentionPolicy .SOURCE, , тогда компилятор Java должен убедиться, что a нет в двоичном представлении класса или , в котором отображается a.
  • Если т есть элемент, значение которого annotation.RetentionPolicy.CLASS или annotation.RetentionPolicy.RUNTIME Java-компилятор должен гарантировать, что будет представлен в двоичном представлении интерфейса класса или , в котором появляется , если m аннотирует локальную переменную . Аннотации в локальном объявлении переменной никогда не сохраняются в двоичном представлении .

Если Т не имеет (мета-) аннотации м, что соответствует annotation.Retention, то Java компилятор должен относиться к T, как если бы оно есть такие мета-аннотации м с элемент, значение которого равно аннотация.RetentionPolicy.CLASS.

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

-1

Аннотации не имеют прямого влияния на работу кода они комментируют.
Однако, используя @Retention(RetentionPolicy.RUNTIME), аннотации становятся доступными во время выполнения.

Теперь, я предполагаю, что @Retention недоступен и поэтому игнорируется. Это означает, что другие аннотации не доступны во время выполнения.
Не существует исключения, поскольку по умолчанию аннотации игнорируются. Рассматриваются только при наличии @Retention.

Возможно, если вы сделаете shure @Retention, будет жалоба. (не уверен об этом)

+5

@Возврат в java.lang.annotation - как он не может быть доступен? –

7

Если у вас на самом деле есть код, который читает @A и что-то с ним делает, код имеет зависимость от класса A, и он будет генерировать ClassNotFoundException.

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

Смежные вопросы