如何在 Java 中从常量向注释提供枚举值

2022-08-31 11:27:13

我无法使用从常量中获取的枚举作为注释中的参数。我收到这个编译错误:“注释属性[属性]的值必须是枚举常量表达式”。

这是枚举代码的简化版本:

public enum MyEnum {
    APPLE, ORANGE
}

对于注释:

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface MyAnnotation {
    String theString();

    int theInt();

    MyEnum theEnum();
}

和类:

public class Sample {
    public static final String STRING_CONSTANT = "hello";
    public static final int INT_CONSTANT = 1;
    public static final MyEnum MYENUM_CONSTANT = MyEnum.APPLE;

    @MyAnnotation(theEnum = MyEnum.APPLE, theInt = 1, theString = "hello")
    public void methodA() {

    }

    @MyAnnotation(theEnum = MYENUM_CONSTANT, theInt = INT_CONSTANT, theString = STRING_CONSTANT)
    public void methodB() {

    }

}

该错误仅显示在方法 B 上的“theEnum = MYENUM_CONSTANT”中。字符串和 int 常量与编译器一起可以,但 Enum 常量则不然,即使它与 over methodA 的值完全相同。在我看来,这是编译器中缺少的一个功能,因为这三个功能显然都是常量。没有方法调用,没有奇怪的类使用等。

我想实现的是:

  • 若要使用MYENUM_CONSTANT在批注和后面的代码中。
  • 为了保持类型安全。

任何实现这些目标的方法都可以。

编辑:

谢谢大家。正如你所说,这是做不到的。应更新 JLS。这次我决定忘记注释中的枚举,并使用常规的int常量。只要 int 是从命名常量赋值的,值就是有界的,并且它是“某种”类型的安全。

它看起来像这样:

public interface MyEnumSimulation {
    public static final int APPLE = 0;
    public static final int ORANGE = 1;
}
...
public static final int MYENUMSIMUL_CONSTANT = MyEnumSimulation.APPLE;
...
@MyAnnotation(theEnumSimulation = MYENUMSIMUL_CONSTANT, theInt = INT_CONSTANT, theString = STRING_CONSTANT)
public void methodB() {
...

我可以在代码中的其他任何地方使用MYENUMSIMUL_CONSTANT。


答案 1

“计算机科学中的所有问题都可以通过另一个层次的间接寻址来解决”,david Wheeler---

在这里:

枚举类:

public enum Gender {
    MALE(Constants.MALE_VALUE), FEMALE(Constants.FEMALE_VALUE);

    Gender(String genderString) {
    }

    public static class Constants {
        public static final String MALE_VALUE = "MALE";
        public static final String FEMALE_VALUE = "FEMALE";
    }
}

人员类:

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import static com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import static com.fasterxml.jackson.annotation.JsonTypeInfo.Id;

@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = Person.GENDER)
@JsonSubTypes({
    @JsonSubTypes.Type(value = Woman.class, name = Gender.Constants.FEMALE_VALUE),
    @JsonSubTypes.Type(value = Man.class, name = Gender.Constants.MALE_VALUE)
})
public abstract class Person {
...
}

答案 2

我认为投票最多的答案是不完整的,因为它根本不能保证枚举值与基础常量 String 值耦合。有了这个解决方案,应该将两个类解耦。

相反,我宁愿建议通过强制枚举名称和常量值之间的相关性来加强该答案中显示的耦合,如下所示:

public enum Gender {
    MALE(Constants.MALE_VALUE), FEMALE(Constants.FEMALE_VALUE);

    Gender(String genderString) {
      if(!genderString.equals(this.name()))
        throw new IllegalArgumentException();
    }

    public static class Constants {
        public static final String MALE_VALUE = "MALE";
        public static final String FEMALE_VALUE = "FEMALE";
    }
}

正如@GhostCat在注释中指出的那样,必须进行适当的单元测试以确保耦合。