Crea istanza di annotazione con impostazioni predefinite, in Java
-
06-07-2019 - |
Domanda
Come posso creare un'istanza della seguente annotazione (con tutti i campi impostati sul loro valore predefinito).
@Retention( RetentionPolicy.RUNTIME )
public @interface Settings {
String a() default "AAA";
String b() default "BBB";
String c() default "CCC";
}
Ho provato nuove impostazioni ()
, ma non sembra funzionare ...
Soluzione 2
Non è possibile creare un'istanza, ma almeno ottenere i valori predefiniti
Settings.class.getMethod("a").getDefaultValue()
Settings.class.getMethod("b").getDefaultValue()
Settings.class.getMethod("c").getDefaultValue()
Quindi, è possibile utilizzare un proxy dinamico per restituire i valori predefiniti. Questo è, per quanto posso dire, il modo in cui le annotazioni sono gestite anche da Java stesso.
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());
Altri suggerimenti
Per creare un'istanza è necessario creare una classe che implementa:
-
java.lang.Annotation
- e l'annotazione che desideri " simula "
Ad esempio:
MySettings di classe pubblica implementa Annotation, Settings
Ma devi prestare particolare attenzione all'implementazione corretta di uguale a
e hashCode
secondo Annotation
interfaccia.
http://download.oracle. com / JavaSE / 1.5.0 / docs / api / java / lang / annotazione / Annotation.html
Se non vuoi implementarlo ancora e ancora, dai un'occhiata a javax.enterprise.util.AnnotationLiteral . Questo fa parte del CDI (Context Dependency Injection) -API. (@vedi codice)
Per ottenere i valori predefiniti è possibile utilizzare il modo descritto da Adrian.
Settings.class.getMethod (" un "). GetDefaultValue ()
Compilo ed eseguo di seguito con risultati soddisfacenti.
class GetSettings {
public static void main (String[] args){
@Settings final class c { }
Settings settings = c.class.getAnnotation(Settings.class);
System.out.println(settings.aaa());
}
}
ha avuto lo stesso problema, l'ho risolto come segue.
public static FieldGroup getDefaultFieldGroup() {
@FieldGroup
class settring {
}
return settring.class.getAnnotation(FieldGroup.class);
}
Se utilizzato con un metodo:
@Settings
public void myMethod() {
}
Ora la tua annotazione è inizializzata con valori predefiniti.
Funziona con Sun / Oracle Java 5,6,7,8: (ma potrebbe potenzialmente rompersi con Java 9 a causa delle classi di sole coinvolte). // modifica Ho appena verificato che funziona ancora con 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)
Esiste una soluzione alternativa, se puoi permetterti di cambiare il corpo della 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;
}
Quindi puoi semplicemente fare riferimento a Settings.DEFAULT_A
(sì, un nome migliore sarebbe d'aiuto!).