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...
To create an instance you need to create a class that implements:
java.lang.Annotation
- and the annotation you want to "simulate"
For example:
public class MySettings implements Annotation, Settings
But you need to pay special attention to the correct implementation of equals
and hashCode
according to the Annotation
interface.
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.AnnotationLiteral class. That is part of the CDI(Context Dependency Injection)-API. (@see code)
To get the default values you can use the way that is described by Adrian.
Settings.class.getMethod("a").getDefaultValue()
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.
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());
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());
}
}
had the same issue, i solved it as follows.
public static FieldGroup getDefaultFieldGroup() {
@FieldGroup
class settring {
}
return settring.class.getAnnotation(FieldGroup.class);
}
If used with a method:
@Settings
public void myMethod() {
}
Now your annotation is initialized with default values.
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.
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)
There is alternative solution, if you can afford to change the body of Settings
class:
@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!).
来源:https://stackoverflow.com/questions/266903/create-annotation-instance-with-defaults-in-java