2010-06-10 17 views
14

creéAsignación de una @annotation ENUM un valor

enum Restrictions{ 
    none, 
    enumeration, 
    fractionDigits, 
    length, 
    maxExclusive, 
    maxInclusive, 
    maxLength, 
    minExclusive, 
    minInclusive, 
    minLength, 
    pattern, 
    totalDigits, 
    whiteSpace; 

    public Restrictions setValue(int value){ 
    this.value = value; 
    return this; 
    } 
    public int value; 
} 

Así que felizmente lo que podía hacer algo como esto, lo cual es perfectamente legal sintaxis.

Restrictions r1 = 
    Restrictions.maxLength.setValue(64); 

La razón es, estoy usando enumeración para restringir el tipo de restricción que podría ser utilizado, y ser capaz de asignar un valor a esa restricción.

Sin embargo, mi verdadera motivación es usar esa restricción en una @anotación.

@Retention(RetentionPolicy.RUNTIME) 
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) 
public @interface Presentable { 
    Restrictions[] restrictions() default Restrictions.none; 
} 

Así que, tenía la intención de hacer esto:

@Presentable(restrictions=Restrictions.maxLength.setValue(64)) 
public String userName; 

la cual, el compilador croaks

The value for annotation enum attribute must be an enum constant expression. 

¿Hay una manera de lograr lo que deseo de lograr

+1

Parece que reinventas 'javax.validation' (JSR303). ¿Has considerado usarlo? ¿Has buscado en su API/impls cómo lo hicieron? P.ej. la [implementación de Hibernate] (http://docs.jboss.org/hibernate/stable/validator/reference/en/html/validator-usingvalidator.html). – BalusC

+0

Hibernate no funciona con GAE, ¿o sí? –

+0

que es el validador de hibernación, no hibernate en sí mismo. eso debería funcionar en todas partes. (cualquiera si no lo hace, tampoco lo hará su versión basada en anotaciones) –

Respuesta

25

Puede hacerlo de esta manera:

import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 

class Person {  
    @Presentable({ 
     @Restriction(type = RestrictionType.LENGTH, value = 5), 
     @Restriction(type = RestrictionType.FRACTION_DIGIT, value = 2) 
    }) 
    public String name; 
} 

enum RestrictionType { 
    NONE, LENGTH, FRACTION_DIGIT; 
} 

@Retention(RetentionPolicy.RUNTIME) 
@interface Restriction { 
    //The below fixes the compile error by changing type from String to RestrictionType 
    RestrictionType type() default RestrictionType.NONE; 
    int value() default 0; 
} 

@Retention(RetentionPolicy.RUNTIME) 
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) 
@interface Presentable { 
    Restriction[] value(); 
} 
+0

De hecho, un mejor enfoque. No pude ver esto en primer lugar, mientras pensaba en la misma línea. +1 –

2

Puede lograr lo que quiera, pero no con enumeraciones directamente.

Si realiza la restricción a una clase regular, con el constructor privado y campos constantes estáticas, a continuación, puede utilizar el método de encadenamiento para crear nuevas instancias fluidez:

enum RestrictionType 
{ 
    none, 
    enumeration, 
    maximumLength, 
    // ... etc. 
} 

class Restriction { 
    static public final Restriction none = new Restriction(RestrictionType.none); 
    static public final Restriction enumeration = new Restriction(RestrictionType.enumeration); 
    static public final Restriction maximumLength = new Restriction(RestrictionType.maximumLength); 

    ... etc 

    RestrictionType type; 
    int value; 

    private Restriction(RestrictionType type) 
    { 
    this(type, 0); 
    } 
    private Restriction(RestrictionType type, int value) 
    { 
    this.type = type; 
    this.value = value; // you don't really need 
    } 

    static public Restriction setValue(int value) 
    { 
     return new Restriction(type, value); 
    } 
} 

que luego se utiliza exactamente como su código original:

@Presentable(restrictions=Restrictions.maxLength.setValue(64)) 
public String userName; 

Sin embargo, me preocupa la falta de OO aquí; si las restricciones tienen un comportamiento diferente o datos necesarios para la definición, terminará agrupando todo en la clase Restricciones. Será mejor crear subclases para los diferentes tipos de restricción.

+0

¿No cree que está creando una nueva instancia en cada invocación del método set? –

+0

public @interface Presentable {Restriction [] restrictions() default Restriction.none;} da como resultado el croar del compilador "solo se permiten los tipos primitivos, String, Class, Annotation o Enum, o 1 arrays atenuadas de los mismos". –

+0

@ h2g2java Haga de 'Restriction' un tipo de anotación. – mdma

3

Una parte del error de compilación, suponga que puede hacer exactamente esto. Entonces, ¿no crees que aplicar la anotación similar en algún otro campo arruinará la primera?

quiero decir,

@Presentable(restrictions=Restrictions.maxLength.setValue(64)) 
public String userName; 
@Presentable(restrictions=Restrictions.maxLength.setValue(32)) 
public String password; 

La misma instancia de ahora tendrá un valor diferente, es decir 32. Así, el 64 se perderán, creo. En el caso, se procesan en tiempo de ejecución secuencialmente, y en el momento en que cambiamos el valor a 32, 64 uno ya ha sido procesado. Entonces, supongo que podemos cambiar el método setter en el ejemplo dado por mdma a algo como a continuación.

static public Restriction setValue(int value) {  
     this.value = value; 
     return this; 
    } 
+0

¡Correcto! Los enums son objetos constantes (compilados a las clases finales) de modo que cada valor enum es un singleton. Los mensajes nunca deben ser objetos mutables, en mi humilde opinión. – bennidi

1

me eligieron Abhin de que la respuesta a mi pregunta, ya que fue la más completa y funcionó cuando lo probé. Sin embargo, documento aquí, en forma de respuesta a mi propia pregunta, lo que realmente hice.

Cambiar el nombre de los términos de Abhin, esto sería cómo iba a aplicarla (similar al ejemplo de Abhin):

@Presentable({ 
@Restrictions(restriction=Restriction.FractionDigits, value="1"), 
@Restrictions(restriction=Restriction.Length, value="10"), 
    ..... 
}) 

Qué decidí es demasiado prolijo. Incluso podría abreviarlo a:

@Presentable({ 
@R(r=R.FractionDigits, v="1"), 
@R(r=R.Length, v="10"), 
    ..... 
}) 

Que podría ser demasiado incomprensible y aún demasiado detallado. Lo que necesitaba era algo que un programador podría especificar con rapidez y de forma global:

@Presentable(sequence = 11, maxLen=64, readOnly=true) 

Por lo tanto, decidí usar la rápida y sucia:

@Retention(RetentionPolicy.RUNTIME) 
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) 
public @interface Presentable { 
    int sequence(); 
    String caption() default ""; 
    int fractionDigits() default -1; 
    int length() default -1; 
    int maxLen() default -1; 
    int minLen() default -1; 
    int totalDigits() default -1; 
    float maxVal() default -1; 
    float minVal() default -1; 
    String pattern() default ""; 
    String whiteSpace() default ""; 
    boolean readOnly() default false; 
    boolean multiValue() default false; 
    boolean hidden() default false; 
    boolean isTest() default true; 
} 

De todos modos, estoy manteniendo la respuesta de Abhin en mis huecos para el futuro utilizar.