what tutorials standard repeatable heritage herencia docs annotation java annotations default

tutorials - trail java



Error al establecer un valor nulo predeterminado para el campo de una anotaciĆ³n (6)

¿Por qué me sale un error? El valor del atributo debe ser constante ". ¿No es nulo constante?

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface SomeInterface { Class<? extends Foo> bar() default null;// this doesn''t compile }


Class<? extends Foo> bar() default null;// this doesn''t compile

Como se mencionó, la especificación del lenguaje Java no permite valores nulos en los valores predeterminados de las anotaciones.

Lo que suelo hacer es hacer es definir constantes DEFAULT_VALUE en la parte superior de la definición de la anotación. Algo como:

public static final String DEFAULT_VALUE = "__class-name-here__ default"; public String prefix() default DEFAULT_VALUE;

Luego, en mi código, hago algo como:

if (myAnnotation.prefix().equals(MyAnnotation.DEFAULT_VALUE)) { ... }

En tu caso con una clase, solo definiría una clase de marcador. Lamentablemente, no puede tener una constante para esto, así que en su lugar debe hacer algo como:

Class<? extends Foo> bar() default DefaultFoo.class;

Su clase DefaultFoo solo sería una implementación vacía para que el código pueda:

if (myAnnotation.bar() == DefaultFoo.class) { ... }

Espero que esto ayude a alguien más.


Ese mensaje de error es engañoso, pero, no, el literal null no es una expresión constante, como se define en la Especificación del lenguaje Java, here .

Además, la Especificación de Lenguaje Java dice:

Es un error en tiempo de compilación si el tipo del elemento no es acorde (§9.7) con el valor predeterminado especificado.

Y para explicar lo que eso significa

Es un error en tiempo de compilación si el tipo de elemento no es proporcional al valor del elemento. Un elemento tipo T es acorde con un valor de elemento V si y solo si uno de los siguientes es verdadero:

  • [...]
  • V no es nulo .

Entonces, aquí, ¿tu tipo de elemento, Class<? extends Foo> Class<? extends Foo> , no es acorde con el valor predeterminado, porque ese valor es null .


No sé por qué, pero el JLS es muy claro:

Discussion Note that null is not a legal element value for any element type.

Y la definición de un elemento predeterminado es:

DefaultValue: default ElementValue

Desafortunadamente, sigo encontrando que las nuevas funciones de idioma (Enumeraciones y ahora Anotaciones) tienen mensajes de error del compilador poco útiles cuando no se cumplen las especificaciones de idioma.

EDITAR: Un poco de google encontró lo following en el JSR-308, donde argumentan para permitir nulos en esta situación:

Observamos algunas posibles objeciones a la propuesta.

La propuesta no hace posible nada que no fuera posible antes.

El valor especial definido por el programador proporciona una mejor documentación que null, lo que podría significar "ninguno", "no inicializado", nulo en sí mismo, etc.

La propuesta es más propensa a errores. Es mucho más fácil olvidarse de la comprobación contra nulo que olvidarse de buscar un valor explícito.

La propuesta puede hacer que el modismo estándar sea más detallado. Actualmente, solo los usuarios de una anotación deben verificar sus valores especiales. Con la propuesta, muchas herramientas que procesan anotaciones deberán verificar si el valor de un campo es nulo para que arrojen una excepción de puntero nulo.

Creo que solo los dos últimos puntos son relevantes para "por qué no hacerlo en primer lugar". El último punto sin duda trae un buen punto: un procesador de anotación nunca tiene que preocuparse de que obtendrán un valor nulo en una anotación. Tiendo a ver que es más el trabajo de los procesadores de anotaciones y otros códigos de frameworks tener que hacer ese tipo de control para hacer que los desarrolladores tengan un código más claro que al revés, pero ciertamente sería difícil justificar el cambio.


Parece que esto es ilegal, aunque el JLS es muy confuso en esto.

Rompí mi memoria para tratar de pensar en una anotación existente que tenía un atributo de Clase en una anotación, y la recordaba de la API de JAXB:

@Retention(RUNTIME) @Target({PACKAGE,FIELD,METHOD,TYPE,PARAMETER}) public @interface XmlJavaTypeAdapter { Class type() default DEFAULT.class; static final class DEFAULT {} }

Puede ver cómo han tenido que definir una clase estática ficticia para contener el equivalente de un nulo.

Desagradable.


Parece que hay otra forma de hacerlo.

Tampoco me gusta esto, pero podría funcionar.

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface SomeInterface { Class<? extends Foo>[] bar() default {}; }

Entonces, básicamente, creas una matriz vacía. Esto parece permitir un valor predeterminado.


Prueba esto

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface SomeInterface { Class bar() default void.class; }

No requiere una nueva clase y ya es una palabra clave en Java que no significa nada.