suppresswarnings sirve retentionpolicy reflexion que para example ejemplo crear anotaciones annotation java annotations instantiation

sirve - Crear instancia de anotación con valores predeterminados, en Java



reflection en java (7)

¿Cómo puedo crear una instancia de la siguiente anotación (con todos los campos establecidos en su valor predeterminado).

@Retention( RetentionPolicy.RUNTIME ) public @interface Settings { String a() default "AAA"; String b() default "BBB"; String c() default "CCC"; }

Probé la new Settings() , pero parece que no funciona ...


No puede crear una instancia, pero al menos obtener los valores predeterminados

Settings.class.getMethod("a").getDefaultValue() Settings.class.getMethod("b").getDefaultValue() Settings.class.getMethod("c").getDefaultValue()

Y luego, un proxy dinámico podría usarse para devolver los valores predeterminados. Que es, por lo que puedo decir, la forma en que las anotaciones son manejadas por Java también.

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());


Para crear una instancia, necesitas crear una clase que implemente:

  • java.lang.Annotation
  • y la anotación que quiere "simular"

Por ejemplo: public class MySettings implements Annotation, Settings

Pero debe prestar especial atención a la implementación correcta de equals y hashCode según la interfaz de Annotation . http://download.oracle.com/javase/1,5.0/docs/api/java/lang/annotation/Annotation.html

Si no desea implementar esto una y otra vez, eche un vistazo a la clase javax.enterprise.util.AnnotationLiteral . Eso es parte de la CDI (Inyección de Dependencia de Contexto) -API. (@see código)

Para obtener los valores predeterminados, puede usar la forma que describe Adrian. Settings.class.getMethod("a").getDefaultValue()


Si se usa con un método:

@Settings public void myMethod() { }

Ahora su anotación se inicializa con valores predeterminados.


tenía el mismo problema, lo resolví de la siguiente manera.

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


Esto funciona con Sun / Oracle Java 5,6,7,8: (pero podría romper con Java 9 debido a las clases de sol involucradas). // edit Acaba de verificar que esto todavía funciona 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; } }

Salida:

Custom annotation creation: @demo.AnnotationProxyExample$Example(bar=true, foo=42, value=required) Traditional annotation creation: @demo.AnnotationProxyExample$Example(bar=true, foo=42, value=required)


Compilo y corrí a continuación con resultados satisfactorios.

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


Existe una solución alternativa, si puede permitirse cambiar el cuerpo de la clase de 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; }

Entonces simplemente puede hacer referencia a Settings.DEFAULT_A (sí, ¡un nombre mejor ayudaría!).