首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Java枚举注释值的枚举默认值

Java枚举注释值的枚举默认值
EN

Stack Overflow用户
提问于 2011-08-16 05:58:33
回答 7查看 14.4K关注 0票数 20

Java允许enum作为注释值的值。如何为enum注释值定义一种通用的缺省enum值?

我已经考虑了以下内容,但它不能编译:

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

    T defaultValue();

}

这个问题有没有解决方案?

BOUNTY

对于这种Java死角的情况,似乎没有直接的解决方案。因此,我正在发起一项赏金,以寻找这个问题最优雅的解决方案。

理想的解决方案理想情况下应满足以下标准:

  1. One批注可在所有枚举上重用
  2. 从批注实例

检索默认枚举值作为枚举所需的工作量/复杂度最低

到目前为止的最佳解决方案

作者:

@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 on字段中搜索所提供的默认值。

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

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2011-08-23 19:54:39

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

答案1:

如果你只想写尽可能少的代码,这里是我的建议,扩展沙丘的答案:

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进行注释。不过,您必须通过annotation对象上的反射访问值。在框架方面,这种方法似乎更复杂。

票数 4
EN

Stack Overflow用户

发布于 2011-08-16 07:34:40

如果构造函数args中没有提供默认值,那么我不能完全确定您所说的获取默认值是什么意思,并且不关心运行时的泛型类型。

下面的方法是可行的,但这是一个丑陋的技巧。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public class Main {

    @MyAnnotation(clazz = MyEnum.class, name = "A")
    private MyEnum value;

    public static v oid main(String[] args) {
        new Main().printValue();
    }

    public void printValue() {
        System.out.println(getValue());
    }

    public MyEnum getValue() {
        if (value == null) {
            value = getDefaultValue("value", MyEnum.class);
        }
        return value;
    }

    private <T extends Enum<?>> T getDefaultValue(String name, Class<T> clazz) {

        try {
            MyAnnotation annotation = Main.class.getDeclaredField(name)
                    .getAnnotation(MyAnnotation.class);

            Method valueOf = clazz.getMethod("valueOf", String.class);

            return clazz.cast(valueOf.invoke(this, annotation.value()));

        } catch (SecurityException e) {
            throw new IllegalStateException(e);
        } catch (NoSuchFieldException e) {
            throw new IllegalArgumentException(name, e);
        } catch (IllegalAccessException e) {
            throw new IllegalStateException(e);
        } catch (NoSuchMethodException e) {
                throw new IllegalStateException(e);
        } catch (InvocationTargetException e) {
            if (e.getCause() instanceof RuntimeException) {
                throw (RuntimeException) e.getCause();
                /* rethrow original runtime exception 
                 * For instance, if value = "C" */
            }
            throw new IllegalStateException(e);
        }
    }

    public enum MyEnum {
        A, B;
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface MyAnnotation {

        Class<? extends Enum<?>> clazz();

        String name();
    }
}

编辑:我通过枚举的valueOf方法更改了getDefaultValue,因此如果给定的值不是枚举的引用实例,则会给出更好的错误消息。

票数 5
EN

Stack Overflow用户

发布于 2011-08-16 06:32:51

简单地说,你不能那样做。枚举不能很容易地用作泛型类型;也许有一个例外,那就是枚举实际上可以实现接口,这允许某种程度上的动态使用。但这不适用于注释,因为可以使用的类型集是严格受限的。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7071301

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档