Comment créer une instance de l'annotation suivante (avec tous les champs définis sur leur valeur par défaut).
@Retention( RetentionPolicy.RUNTIME )
public @interface Settings {
String a() default "AAA";
String b() default "BBB";
String c() default "CCC";
}
J'ai essayé new Settings()
, mais cela ne semble pas fonctionner ...
Vous ne pouvez pas créer une instance, mais au moins obtenir les valeurs par défaut
Settings.class.getMethod("a").getDefaultValue()
Settings.class.getMethod("b").getDefaultValue()
Settings.class.getMethod("c").getDefaultValue()
Et puis, un proxy dynamique pourrait être utilisé pour renvoyer les valeurs par défaut. Autant que je sache, Java gère également les annotations.
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());
Pour créer une instance, vous devez créer une classe qui implémente:
Java.lang.Annotation
Par exemple: public class MySettings implements Annotation, Settings
Mais vous devez accorder une attention particulière à la correct implémentation de equals
et hashCode
en fonction de l'interface Annotation
. Http://download.Oracle.com/javase/1,5.0 /docs/api/Java/lang/annotation/Annotation.html
Si vous ne voulez pas implémenter cela encore et encore, jetez un coup d'œil à la classe javax.enterprise.util.AnnotationLiteral . Cela fait partie de CDI (Context Dependency Injection) -API . (@voir code) }
Pour obtenir les valeurs par défaut, vous pouvez utiliser la manière décrite par Adrian. Settings.class.getMethod("a").getDefaultValue()
J'ai compilé et couru ci-dessous avec des résultats satisfaisants.
class GetSettings {
public static void main (String[] args){
@Settings final class c { }
Settings settings = c.class.getAnnotation(Settings.class);
System.out.println(settings.aaa());
}
}
eu le même problème, je l'ai résolu comme suit.
public static FieldGroup getDefaultFieldGroup() {
@FieldGroup
class settring {
}
return settring.class.getAnnotation(FieldGroup.class);
}
Si utilisé avec une méthode:
@Settings
public void myMethod() {
}
Votre annotation est maintenant initialisée avec les valeurs par défaut.
Cela fonctionne avec Sun/Oracle Java 5,6,7,8: (mais pourrait éventuellement rompre avec Java 9 en raison des classes Sun concernées). // edit Nous venons de vérifier que cela fonctionne toujours avec 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;
}
}
Sortie:
Custom annotation creation: @demo.AnnotationProxyExample$Example(bar=true, foo=42, value=required)
Traditional annotation creation: @demo.AnnotationProxyExample$Example(bar=true, foo=42, value=required)
Il existe une solution alternative, si vous pouvez vous permettre de changer le corps de la classe 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;
}
Ensuite, vous pouvez simplement référencer Settings.DEFAULT_A
(oui, un meilleur nom aiderait!).