¿Por qué recibo un error "El valor del atributo debe ser constante"? ¿No es nula constante ???
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SomeInterface {
Class<? extends Foo> bar() default null;// this doesn't compile
}
java
annotations
default
destripador234
fuente
fuente
Class<? extends Foo> bar();
.Respuestas:
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 del lenguaje (Enums y ahora Anotaciones) tienen mensajes de error del compilador muy inútiles cuando no cumples con las especificaciones del lenguaje.
EDITAR: Un poco de búsqueda en Google encontró lo siguiente en el JSR-308, donde argumentan a favor de permitir nulos en esta situación:
Creo que solo los dos últimos puntos son relevantes para "por qué no hacerlo en primer lugar". El último punto ciertamente trae a colación un buen punto: un procesador de anotaciones nunca tiene que preocuparse de que obtendrán un valor nulo en un valor de anotación. Tiendo a ver eso como más trabajo de los procesadores de anotaciones y otro código de marco similar tener que hacer ese tipo de verificación para que el código de los desarrolladores sea más claro en lugar de al revés, pero ciertamente haría difícil justificar el cambio.
fuente
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.
fuente
Class<? extends Foo> bar() default void.null
no se compila.Parecería que esto es ilegal, aunque el JLS es muy confuso al respecto.
Arruiné mi memoria para intentar pensar en una anotación existente que tuviera un atributo de clase para una anotación, y recordé esta 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 mantener el equivalente a un valor nulo.
Desagradable.
fuente
Parece que hay otra forma de hacerlo.
Esto tampoco me gusta, 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 en su lugar. Esto parece permitir un valor predeterminado.
fuente
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 definir
DEFAULT_VALUE
constantes en la parte superior de la definición de la anotación. Algo como:public @interface MyAnnotation { public static final String DEFAULT_PREFIX = "__class-name-here__ default"; ... public String prefix() default DEFAULT_PREFIX; }
Luego en mi código hago algo como:
if (myAnnotation.prefix().equals(MyAnnotation.DEFAULT_PREFIX)) { ... }
En su caso con una clase, simplemente definiría una clase de marcador. Desafortunadamente, no puede tener una constante para esto, por lo que debe hacer algo como:
public @interface MyAnnotation { public static Class<? extends Foo> DEFAULT_BAR = DefaultBar.class; ... Class<? extends Foo> bar() default DEFAULT_BAR; }
Su
DefaultFoo
clase sería solo una implementación vacía para que el código pueda hacer:if (myAnnotation.bar() == MyAnnotation.DEFAULT_BAR) { ... }
Espero que esto ayude.
fuente
.equals()
y no==
@Doradus? ¿Obtuvo un valor diferente o un objeto diferente?==
..equals()
. Sorprendente.Ese mensaje de error es confuso, pero no, el
null
literal no es una expresión constante, como se define en la especificación del lenguaje Java, aquí .Además, la especificación del lenguaje Java dice
Y para explicar lo que eso significa
Entonces, aquí, su tipo de elemento
Class<? extends Foo>
,, no es acorde con el valor predeterminado, porque ese valor esnull
.fuente
or
y un interiorand
, que no se pueden dejar de lado.Como han dicho otros, hay una regla que dice que nulo no es un valor predeterminado válido en Java.
Si tiene un número limitado de valores posibles que puede tener el campo , entonces una opción para solucionar esto es hacer que el tipo de campo sea una enumeración personalizada que a su vez contenga una asignación a nulo. Por ejemplo, imagina que tengo la siguiente anotación para la que quiero un valor nulo predeterminado:
public @interface MyAnnotation { Class<?> value() default null; }
Como hemos establecido, esto no está permitido. Lo que podemos hacer en cambio es definir una enumeración:
public enum MyClassEnum { NULL(null), MY_CLASS1(MyClass1.class), MY_CLASS2(MyClass2.class), ; public final Class<?> myClass; MyClassEnum(Class<?> aClass) { myClass = aClass; } }
y cambie la anotación como tal:
public @interface MyAnnotation { MyClassEnum value() default MyClassEnum.NULL; }
La principal desventaja de esto (además de tener que enumerar sus posibles valores) es que ahora ha envuelto su valor en una enumeración, por lo que deberá invocar la propiedad / captador en la enumeración para obtener el valor.
fuente