Присваивание перечислению @Annotation значения - PullRequest
15 голосов
/ 10 июня 2010

Я создал

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

Чтобы я мог с радостью сделать что-то подобное, совершенно законный синтаксис.

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

Причина в том, что я использую enum , чтобы ограничить тип ограничения, которое можно использовать, и могу присвоить значение этому ограничению .

Однако моя реальная мотивация - использовать это ограничение в аннотации @.

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

Итак, я намеревался сделать это:

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

на что, квакает компилятор

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

Есть ли способ выполнить то, что я хочу достичь

Ответы [ 4 ]

26 голосов
/ 11 июня 2010

Вы можете сделать это так:

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();
}
3 голосов
/ 11 июня 2010

Часть из ошибки компиляции, предположим, что вы можете сделать именно это. Тогда вы не думаете, что применение аналогичной аннотации к другому полю испортит первое?

Я хочу сказать,

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

Тот же экземпляр теперь будет иметь другое значение, то есть 32. Таким образом, 64, я считаю, будут потеряны. В случае, если они обрабатываются во время выполнения последовательно, и в тот момент, когда мы меняем значение на 32, 64, оно уже было обработано. Тогда, я полагаю, мы можем изменить метод setter в примере, заданном mdma, на что-то вроде ниже.

 static public Restriction setValue(int value) {    
      this.value = value;
      return this;
  }
2 голосов
/ 10 июня 2010

Вы можете достичь того, что хотите, но не с помощью перечислений напрямую.

Если вы сделаете Restriction обычным классом с частным конструктором и полями статической константы, вы сможете использовать цепочку методов для быстрого создания новых экземпляров:

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

Который затем используется именно как ваш исходный код:

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

Тем не менее, я обеспокоен отсутствием ОО здесь - если ограничения имеют другое поведение или данные, необходимые для определения, тогда вы в конечном итоге будете смешивать все в классе «Ограничения». Будет лучше создать подклассы для разных типов ограничений.

1 голос
/ 14 июня 2010

Я выбрал Abhin's в качестве ответа на мой вопрос, потому что он был наиболее полным и сработал, когда я его опробовал. Тем не менее, я документирую здесь, в форме ответа на свой вопрос, что я на самом деле сделал.

Переименовывая термины Абхина, я бы применил их (аналогично примеру Абхина):

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

То, что я решил, слишком многословно. Я мог бы даже сократить его до:

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

Что может быть слишком непонятным и все же многословным. Мне нужно было что-то, что программист мог бы определить быстро и всесторонне:

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

Поэтому я решил использовать быстрое и грязное:

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

В любом случае, я храню ответ Абина в своих тайниках для будущего использования.

...