Java允许将enum作为注释值的值。如何为enum批注值定义一种通用的默认enum值?

我考虑过以下内容,但无法编译:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public <T extends Enum<T>> @interface MyAnnotation<T> {

    T defaultValue();

}

是否有解决此问题的方法?

BOUNTY

对于这种Java极端情况,似乎没有直接解决方案。因此,我开始悬赏金以找到针对此问题的最优雅的解决方案。

理想的解决方案理想地应满足以下条件:
  • 可在所有枚举上重用的一个批注
  • 从注释实例
  • 中检索默认枚举值作为枚举的最小工作量/复杂度

    最佳解决方案

    沙丘:
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface MyAnnotation {
    
        // By not specifying default,
        // we force the user to specify values
        Class<? extends Enum<?>> enumClazz();
        String defaultValue();
    
    }
    
    ...
    
    public enum MyEnumType {
        A, B, D, Q;
    }
    
    ...
    
    // Usage
    @MyAnnotation(enumClazz=MyEnumType.class, defaultValue="A");
    private MyEnumType myEnumField;
    

    当然,我们不能强制用户在编译时指定有效的默认值。但是,任何注释预处理都可以使用valueOf()进行验证。

    改进

    Arian提供了一种优雅的解决方案来摆脱带注释字段中的clazz:
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface MyAnnotation {
    
    }
    
    ...
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    @MyAnnotation()
    public @interface MyEnumAnnotation {
    
        MyEnumType value(); // no default has user define default value
    
    }
    
    ...
    
    @MyEnumAnnotation(MyEnum.FOO)
    private MyEnumType myValue;
    

    注释处理器应在字段中搜索两个MyEnumAnnotation以获得所提供的默认值。

    这需要为每个枚举类型创建一个注释类型,但要保证编译时检查类型的安全性。

    最佳答案

    我不确定您的用例是什么,所以我有两个答案:

    答案1:

    如果您只想编写尽可能少的代码,这是我的建议,扩展 Dunes的答案:

    public enum ImplicitType {
        DO_NOT_USE;
    }
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface MyAnnotation {
    
        Class<? extends Enum<?>> clazz() default ImplicitType.class;
    
        String value();
    }
    
    @MyAnnotation("A");
    private MyEnumType myEnumField;
    

    clazzImplicitType.class时,将字段类型用作枚举类。

    答案2:

    如果您想做一些框架魔术,并且想要维护编译器检查的类型安全,则可以执行以下操作:
    /** Marks annotation types that provide MyRelevantData */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface MyAnnotation {
    }
    

    在客户端代码中,您将拥有
    /** Provides MyRelevantData for TheFramework */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    @MyAnnotation
    public @interface MyEnumAnnotation {
    
        MyEnumType value(); // default MyEnumType.FOO;
    
    }
    
    @MyEnumAnnotation(MyEnum.FOO)
    private MyEnumType myValue;
    

    在这种情况下,您将在字段中扫描以再次使用MyAnnotation进行注释的注释。但是,您将必须通过反射在注释对象上访问该值。在框架方面,这种方法似乎更复杂。

    09-10 08:30
    查看更多