2010-08-25 9 views
76

Considere el siguiente código:¿Por qué una anotación faltante no causa una ClassNotFoundException en tiempo de ejecución?

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())); 
     } 
} 

Compilación y ejecución de las obras como se esperaba:

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

Pero entonces considerar esto:

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

Hubiera esperado lanzar un ClassNotFoundException, ya que @A falta. Pero, en cambio, deja caer la anotación en silencio.

¿Está documentado este comportamiento en el JLS en alguna parte, o es una peculiaridad de la JVM de Sun? ¿Cuál es la razón para esto?

Parece conveniente para cosas como javax.annotation.Nonnull (que parece que debería haber sido @Retention(CLASS) de todos modos), pero para muchas otras anotaciones parece que podría causar varias cosas malas en el tiempo de ejecución.

Respuesta

81

En los borradores públicos anteriores para JSR-175 (anotaciones), se discutió si el compilador y el tiempo de ejecución deberían ignorar las anotaciones desconocidas para proporcionar un acoplamiento más flexible entre el uso y la declaración de anotaciones. Un ejemplo específico fue el uso de anotaciones específicas del servidor de aplicaciones en un EJB para controlar la configuración de implementación. Si el mismo bean se implementara en un servidor de aplicaciones diferente, hubiera sido conveniente si el tiempo de ejecución simplemente ignoró las anotaciones desconocidas en lugar de generar un NoClassDefFoundError.

Incluso si la redacción es un poco vaga, supongo que el comportamiento que está viendo se especifica en JLS 13.5.7: "... eliminar anotaciones no tiene ningún efecto sobre el enlace correcto de las representaciones binarias de los programas en el lenguaje de programación de Java ". Interpreto esto como si se eliminaran las anotaciones (no disponible en tiempo de ejecución), el programa aún debe vincularse y ejecutarse, y eso implica que las anotaciones desconocidas simplemente se ignoran cuando se accede a ellas a través de la reflexión.

La primera versión de Sun's JDK 5 no implementó esto correctamente, pero se corrigió en 1.5.0_06. Puede encontrar el error relevante 6322301 en la base de datos de errores, pero no apunta a ninguna especificación, excepto que alega que "de acuerdo con la especificación JSR-175, las anotaciones desconocidas deben ser ignoradas por getAnnotations".

32

Citando el JLS:

9.6.1.2 Retención Anotaciones puede estar presente sólo en el código fuente, o que puede estar presente en la forma binaria de una clase o interfaz. Una anotación que está presente en el archivo binario may o puede no estar disponible en tiempo de ejecución a través de las bibliotecas reflexivas de la plataforma Java .

El tipo de anotación anotación.Retención se utiliza para elegir entre las posibilidades anteriores. Si un anotación A corresponde a un tipo T, y T tiene un (meta) anotación m que corresponde a annotation.Retention, entonces:

  • Si m tiene un elemento cuyo valor es annotation.RetentionPolicy .SOURCE, a continuación, un compilador de Java debe garantizar que a no está presente en la representación binaria de la clase interfaz en la que aparece a.
  • Si m tiene un elemento cuyo valor es annotation.RetentionPolicy.CLASS o annotation.RetentionPolicy.RUNTIME un compilador de Java debe asegurar que una se representados en el binario representación de la interfaz de la clase o en el que aparece una , a menos que m anote una variable local declaración. Una anotación en una declaración de variable local nunca se retiene en la representación binaria.

Si T no tiene un (meta) anotación m que corresponde a annotation.Retention, a continuación, un compilador Java debe tratar a T como si no tiene como un meta-m con una anotación elemento cuyo valor es annotation.RetentionPolicy.CLASS.

Así RetentionPolicy.RUNTIME asegura que la anotación está compilado en el binario, pero una anotación presente en el binario no tiene que estar disponible en tiempo de ejecución

-1

Anotaciones tienen ningún efecto directo sobre el funcionamiento del código ellos anotan Sin embargo, al usar @Retention(RetentionPolicy.RUNTIME), las anotaciones estarán disponibles en tiempo de ejecución.

Ahora, supongo que @Retention no está disponible y, por lo tanto, se ignora. Esto implica que las otras anotaciones no están disponibles en tiempo de ejecución.
No hay excepción porque las anotaciones se ignoran por defecto. Solo en presencia de @Retention se consideran.

Probablemente si haces shure @Retention está disponible, habrá una queja. (no estoy seguro de esto)

+5

@Retention está en java.lang.annotation - ¿cómo podría no estar disponible? –

7

si realmente tiene un código que lee @A y hace algo con él, el código tiene una dependencia en la clase A, y lanzará ClassNotFoundException.

si no, es decir, ningún código se preocupa específicamente por @A, entonces es discutible que @A en realidad no importe.

Cuestiones relacionadas