2009-07-24 12 views

Respuesta

52

no sé por qué, pero el JLS es muy clara:

Discussion 

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

y la definición de un elemento por defecto es:

 DefaultValue: 
     default ElementValue 

Lamentablemente sigo encontrando que las nuevas características del lenguaje (Enumeraciones y ahora Anotaciones) tienen mensajes de error del compilador poco útiles cuando no se cumplen las especificaciones de idioma.

EDIT: Un poco Googleing encontró el following en el JSR-308, en el que argumentan a favor de permitir que los nulos en esta situación:

Observamos algunas posibles objeciones a la propuesta.

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

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

La propuesta es más propenso 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 la expresión estándar sea más detallada. 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.

41

Parecería que esto es ilegal, aunque el JLS es muy confuso en esto.

Me sacudido mi memoria para tratar de pensar en una anotación existente por ahí que tenía un atributo de clase para una anotación, y se acordó de éste de la API JAXB:

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

    static final class DEFAULT {}  
} 

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

desagradable.

+2

Sí, hacemos algo similar (simplemente usamos Foo.class como valor predeterminado). Sucks. – ripper234

+5

Y en el caso de los campos String, debe recurrir a [magic strings] (http://en.wikipedia.org/wiki/Magic_string). Aparentemente, los antipatrones conocidos son mejores que las características del lenguaje bien conocidas en la actualidad. –

+2

@TimYates Me mata ver a las personas definir su propio valor centinela "sin valor" cuando null está disponible y se entiende universalmente. ¡Y ahora el idioma en sí lo exige! Afortunadamente, puede definir sus "cadenas mágicas" como constantes públicas. Todavía no es ideal, pero al menos el código que busca su anotación puede hacer referencia a la constante en lugar de usar literales en todas partes. – spaaarky21

46

probar este

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

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

+6

Me gusta. El único problema, en el contexto de la pregunta original, es que esta respuesta no admite parámetros de tipo: 'Class bar() default void.null' no compila. – Kariem

+1

The void.class no se puede aplicar en general: public @interface NoNullDefault {String value() default void.class; } – wjohnson

+0

Para Groovy funciona bien, incluso en los casos mencionados en los comentarios – Vampire

9

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 {}; 
} 

Así que, básicamente, usted crea una matriz vacía en su lugar. Esto parece permitir un valor predeterminado.

1

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 de lenguaje Java, here.

Por otra parte, el Java Language Specification dice

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

Y para explain what that means

Es un error en tiempo de compilación si el tipo de elemento no se corresponde con el valor elemento. un tipo de elemento T es acorde con un valor elemento V si y sólo si uno de lo siguiente es cierto:

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

Así que aquí, el tipo de elemento, Class<? extends Foo>, no es acorde con el valor por defecto, debido a que el valor es null.

+0

¿Me salió algo mal? –

+0

Su solución no es adecuada para copiar y pegar ;-) A algunos no les gusta pensar, al leer –

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

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

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

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

public String prefix() default DEFAULT_VALUE; 

Luego, en mi código que hago algo así como:

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

En caso de que con una clase, me acaba de definir una clase de marcador. Por desgracia no se puede tener una constante de este modo su lugar usted necesita para hacer algo como:

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

Su clase DefaultFoo sería simplemente una implementación vacío, por lo que el código puede hacer:

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

Esperanza esta ayuda a alguien más

Cuestiones relacionadas