Назначение переменной @Annotation перечисляет значение

Я создал

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 , чтобы ограничить тип ограничения, который может быть использован, и иметь возможность назначить значение этому ограничению.

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

@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.

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

Ответы

Ответ 1

Вы можете сделать это следующим образом:

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

Ответ 2

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

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

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

Ответ 3

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

Если вы создаете 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;

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

Ответ 4

Я выбрал Абхина как ответ на мой вопрос, потому что он был наиболее полным, и он работал, когда я это пробовал. Однако я документирую здесь, в форме ответа на свой вопрос, что я на самом деле сделал.

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

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

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