Я создал
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);
Так как причина, я использую перечисление для ограничения типа ограничения, которое могло использоваться, и смочь присвоить значение тому ограничению.
Однако моя фактическая мотивация должна использовать то ограничение в @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.
Есть ли способ выполнить то, что я хочу выполнить
Вы можете сделать это так:
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();
}
Часть от ошибки компиляции, предположим, что вы способны сделать именно это. Тогда не думаете ли вы, что применение аналогичной аннотации к какому-то другому полю разрушит первое?
То есть,
@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;
}
Вы можете добиться того, чего хотите, но не напрямую с помощью перечислений.
Если вы сделаете 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;
Однако я Меня беспокоит отсутствие здесь объектно-ориентированного подхода - если ограничения имеют другое поведение или данные, необходимые для определения, тогда вы в конечном итоге объедините все в класс Restrictions. Лучше создать подклассы для разных типов ограничений.
Я выбрал ответ Абина в качестве ответа на свой вопрос, потому что он был наиболее исчерпывающим и работал, когда я его пробовал. Однако я документирую здесь в форме ответа на свой вопрос, что я на самом деле сделал.
Переименовывая термины Абхина, я бы применил их следующим образом (аналогично примеру Абхина):
@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;
}
В любом случае, я храню ответ Абина в своих тайниках для будущего использования.