Назначение переменной @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;
}
Во всяком случае, я держу Абхина в своих перерывах для будущего использования.