Expanding on this question: Create Annotation instance with defaults, in Java
I am trying to add a default annotation instance as a field on the annotation:
import java.lang.annotation.*;
import java.util.function.Supplier;
public class AnnoTester {
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.TYPE })
public static @interface Anno {
Anno DEFAULT = annotation(() -> {
@Anno
class Default {}
return Default.class;
}, Anno.class);
String s() default "s";
}
@Anno(s = "T")
public static class TestClass {}
private static <T extends Annotation> T annotation(Supplier<Class<?>> supplier,
Class<T> annotationClass) {
return supplier.get().getAnnotation(annotationClass);
}
public static void main(String[] args) {
System.out.println(Anno.DEFAULT.s()); // NullPointerException if removed
System.out.println(TestClass.class.getAnnotation(Anno.class).s());
}
}
Running this gives the desired response of s
and T
. However if I remove the reference to Anno.DEFAULT
in main()
the code fails to initialize the annotation (stack trace below).
In this case, the annotation proxy created behind the scenes seems to be missing annotationType()
.
Is there a way to fix this without moving DEFAULT
outside the annotation declaration?
Exception in thread "main" java.lang.ExceptionInInitializerError
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:375)
at jdk.proxy2/jdk.proxy2.$Proxy1.<clinit>(Unknown Source)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:78)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at java.base/java.lang.reflect.Proxy.newProxyInstance(Proxy.java:1044)
at java.base/java.lang.reflect.Proxy.newProxyInstance(Proxy.java:1030)
at java.base/sun.reflect.annotation.AnnotationParser$1.run(AnnotationParser.java:306)
at java.base/sun.reflect.annotation.AnnotationParser$1.run(AnnotationParser.java:304)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:312)
at java.base/sun.reflect.annotation.AnnotationParser.annotationForMap(AnnotationParser.java:304)
at java.base/sun.reflect.annotation.AnnotationParser.parseAnnotation2(AnnotationParser.java:294)
at java.base/sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:121)
at java.base/sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:73)
at java.base/java.lang.Class.createAnnotationData(Class.java:3997)
at java.base/java.lang.Class.annotationData(Class.java:3986)
at java.base/java.lang.Class.getAnnotation(Class.java:3869)
at AnnoTester.main(AnnoTester.java:30)
Caused by: java.lang.NullPointerException: Cannot invoke "java.lang.reflect.Method.getName()" because "method" is null
at java.base/sun.reflect.annotation.AnnotationInvocationHandler.invoke(AnnotationInvocationHandler.java:61)
at jdk.proxy2/jdk.proxy2.$Proxy1.annotationType(Unknown Source)
at java.base/sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:123)
at java.base/sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:73)
at java.base/java.lang.Class.createAnnotationData(Class.java:3997)
at java.base/java.lang.Class.annotationData(Class.java:3986)
at java.base/java.lang.Class.getAnnotation(Class.java:3869)
at AnnoTester.annotation(AnnoTester.java:25)
at AnnoTester$Anno.<clinit>(AnnoTester.java:11)
... 21 more