在 Java 中创建具有默认值的 Annotation 实例

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/266903/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 12:14:25  来源:igfitidea点击:

Create Annotation instance with defaults, in Java

javaannotationsinstantiation

提问by akuhn

How can I create an instance of the following annotation (with all fields set to their default value).

如何创建以下注释的实例(所有字段都设置为其默认值)。

    @Retention( RetentionPolicy.RUNTIME )
    public @interface Settings {
            String a() default "AAA";
            String b() default "BBB";
            String c() default "CCC";
    }

I tried new Settings(), but that does not seem to work...

我试过了new Settings(),但这似乎不起作用......

采纳答案by akuhn

You cannot create an instance, but at least get the default values

您无法创建实例,但至少可以获得默认值

Settings.class.getMethod("a").getDefaultValue()
Settings.class.getMethod("b").getDefaultValue()
Settings.class.getMethod("c").getDefaultValue()

And then, a dynamic proxy could be used to return the default values. Which is, as far as I can tell, the way annotations are handled by Java itself also.

然后,可以使用动态代理来返回默认值。据我所知,Java 本身也处理注释的方式。

class Defaults implements InvocationHandler {
  public static <A extends Annotation> A of(Class<A> annotation) {
    return (A) Proxy.newProxyInstance(annotation.getClassLoader(),
        new Class[] {annotation}, new Defaults());
  }
  public Object invoke(Object proxy, Method method, Object[] args)
      throws Throwable {
    return method.getDefaultValue();
  }
}

Settings s = Defaults.of(Settings.class);
System.out.printf("%s\n%s\n%s\n", s.a(), s.b(), s.c());

回答by Florin

If used with a method:

如果与方法一起使用:

@Settings
public void myMethod() {
}

Now your annotation is initialized with default values.

现在您的注释已使用默认值初始化。

回答by emory

I compile and ran below with satisfactory results.

我编译并在下面运行,结果令人满意。

class GetSettings {
    public static void main (String[] args){
      @Settings final class c { }
      Settings settings = c.class.getAnnotation(Settings.class);
      System.out.println(settings.aaa());
    }
}

回答by Ralph

To create an instance you need to create a class that implements:

要创建一个实例,您需要创建一个实现以下内容的类:

For example: public class MySettings implements Annotation, Settings

例如: public class MySettings implements Annotation, Settings

But you need to pay special attention to the correctimplementation of equalsand hashCodeaccording to the Annotationinterface. http://download.oracle.com/javase/1.5.0/docs/api/java/lang/annotation/Annotation.html

但是你需要特别注意正确实现equalshashCode根据Annotation接口。 http://download.oracle.com/javase/1.5.0/docs/api/java/lang/annotation/Annotation.html

If you do not want to implement this again and again then have a look at the javax.enterprise.util.AnnotationLiteralclass. That is part of the CDI(Context Dependency Injection)-API. (@see code)

如果您不想一次又一次地实现这一点,请查看javax.enterprise.util.AnnotationLiteral类。这是 CDI(上下文依赖注入)-API 的一部分。 (@查看代码)

To get the default values you can use the way that is described by akuhn (former known as: Adrian). Settings.class.getMethod("a").getDefaultValue()

要获得默认值,您可以使用 akuhn(以前称为:Adrian)描述的方式。 Settings.class.getMethod("a").getDefaultValue()

回答by ex0b1t

had the same issue, i solved it as follows.

有同样的问题,我解决了如下。

public static FieldGroup getDefaultFieldGroup() {
    @FieldGroup
    class settring {
    }
    return settring.class.getAnnotation(FieldGroup.class);
}

回答by Thomas Darimont

This works with Sun/Oracle Java 5,6,7,8: (but could potentially break with Java 9 due to the sun classes involved). //edit Just verified that this still works with OpenJDK 9b59.

这适用于 Sun/Oracle Java 5,6,7,8:(但由于涉及到 Sun 类,可能会与 Java 9 中断)。//edit 刚刚验证这仍然适用于 OpenJDK 9b59。

package demo;

import sun.reflect.annotation.AnnotationParser;

import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class AnnotationProxyExample
{

    public static void main(String[] args)
    {

        System.out.printf("Custom annotation creation: %s%n", 
                createAnnotationInstance(Collections.singletonMap("value", "required"), Example.class));

        System.out.printf("Traditional annotation creation: %s%n", 
                X.class.getAnnotation(Example.class));
    }

    private static <A extends Annotation> A createAnnotationInstance(Map<String, Object> customValues, Class<A> annotationType)
    {

        Map<String, Object> values = new HashMap<>();

        //Extract default values from annotation
        for (Method method : annotationType.getDeclaredMethods())
        {
            values.put(method.getName(), method.getDefaultValue());
        }

        //Populate required values
        values.putAll(customValues);

        return (A) AnnotationParser.annotationForMap(annotationType, values);
    }

    @Example("required")
    static class X
    {
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @interface Example
    {
        String value();
        int foo() default 42;
        boolean bar() default true;
    }
}

Output:

输出:

Custom annotation creation: @demo.AnnotationProxyExample$Example(bar=true, foo=42, value=required)
Traditional annotation creation: @demo.AnnotationProxyExample$Example(bar=true, foo=42, value=required)

回答by mindas

There is alternative solution, if you can afford to change the body of Settingsclass:

如果您负担得起更改Settings类的主体,则有替代解决方案:

@Retention( RetentionPolicy.RUNTIME )
public @interface Settings {
        String DEFAULT_A = "AAA";
        String DEFAULT_B = "BBB";
        String DEFAULT_C = "CCC";

        String a() default DEFAULT_A;
        String b() default DEFAULT_B;
        String c() default DEFAULT_C;
}

Then you can simply reference Settings.DEFAULT_A(yes, a better name would help!).

然后你可以简单地引用Settings.DEFAULT_A(是的,一个更好的名字会有所帮助!)。