在Java中使用默认值创建注释实例

在Java中使用默认值创建注释实例,java,annotations,instantiation,Java,Annotations,Instantiation,如何创建以下注释的实例(所有字段都设置为默认值) 我尝试了新设置(),但似乎不起作用…如果与方法一起使用: @Settings public void myMethod() { } 现在,您的批注已使用默认值初始化。您无法创建实例,但至少可以获得默认值 Settings.class.getMethod("a").getDefaultValue() Settings.class.getMethod("b").getDefaultValue() Settings.class.getMethod("

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

我尝试了
新设置()
,但似乎不起作用…

如果与方法一起使用:

@Settings
public void myMethod() {
}

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

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

Settings.class.getMethod("a").getDefaultValue()
Settings.class.getMethod("b").getDefaultValue()
Settings.class.getMethod("c").getDefaultValue()
然后,可以使用动态代理返回默认值。就我所知,这也是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());
类默认值实现调用处理程序{
的公共静态A(类注释){
返回(A)Proxy.newProxyInstance(annotation.getClassLoader(),
新类[]{annotation},新默认值();
}
公共对象调用(对象代理、方法、对象[]参数)
扔掉的{
返回方法.getDefaultValue();
}
}
设置s=默认值.of(Settings.class);
System.out.printf(“%s\n%s\n%s\n”,s.a(),s.b(),s.c());

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

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

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

  • 以及要“模拟”的注释
例如:
公共类MySettings实现注释、设置

但是您需要特别注意根据
注释
界面对
equals
hashCode
正确实现。

如果您不想一次又一次地实现它,那么请查看该类。 这是CDI(上下文依赖注入)API的一部分。

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

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

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

这适用于Sun/OracleJava5,6,7,8:(但由于涉及Sun类,可能会与Java9发生冲突)。 //edit刚刚验证了这仍然适用于openjdk9b59

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;
    }
}

如果您有能力更改
设置
类的主体,则有另一种解决方案:

@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;
}

然后您可以简单地引用
设置。默认设置(是的,更好的名称会有帮助!)。

本地类,我总是忘记它们,很好的黑客!实际上,这一个看起来可能比当前接受的答案更好,因为它一直保持静态输入。而当前接受的答案依赖于字符串中的方法名称。@SaM不完全正确,接受的解决方案对传递给代理的方法对象调用
getDefaultValue
。这与Java本身实现注释的方式相同,因此它与您的注释一样“类型安全”。(使用字符串选择方法的初始代码示例仅用于说明原理。)@akuhn这更好。方法名称没有拼写错误。无需将DefaultValue强制转换为字符串。这很好-但如果保留策略为SOURCE,则不起作用:/annotation的“您无法创建实例”是错误的!可以创建注释的实例。您只需要创建一个实现java.lang.annotation.annotation和具体注释接口(例如设置)的类,然后就可以创建该类的实例。更多详情请参见我的答案谢谢您的解决方案!从技术上讲,您可以创建批注子类的实例,就像运行时代理一样。@akuhn,您还可以将@SuppressWarnings(“未选中”)添加到工厂方法“of”;虽然带有抑制警告的typecast看起来并不干净,但我喜欢您的解决方案,因为它确实是类型安全的,并且允许安全地使用IDE的重构功能。谢谢!工作得很好,但是如果有没有默认值的基本成员,它就会崩溃。使用com.google.common.base.Defaults可以执行以下操作:return method.getDefaultValue()!=无效的method.getDefaultValue():Defaults.defaultValue(method.getReturnType());美丽的。诚实的真漂亮。我自己也尝试过,它应该成为这个问题的认可解决方案。你认为这个解决方案需要手动实现注释的每个“方法”吗?@Adrian:对,你必须实现注释定义的接口。--如果您需要方法
a()
b()
c()
,至少在使用Eclipse时,您必须为实现提供注释的完全限定名称。这将编译错误减少为警告。
java.lang.Annotation
不存在,是否应该是
java.lang.Annotation.Annotation
?如果是这样,显式实现它有什么意义,因为它是任何注释的超级接口。
Custom annotation creation: @demo.AnnotationProxyExample$Example(bar=true, foo=42, value=required)
Traditional annotation creation: @demo.AnnotationProxyExample$Example(bar=true, foo=42, value=required)
@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;
}