java - tutorial - Cómo crear una instancia de una anotación
spring java tutorial (4)
Estoy tratando de hacer algo de magia de anotación Java. Debo decir que todavía estoy poniéndome al día con los trucos de anotación y que ciertas cosas aún no están del todo claras para mí.
Entonces ... tengo algunas clases, métodos y campos anotados. Tengo un método, que utiliza la reflexión para ejecutar algunos controles en las clases e inyectar algunos valores en una clase. Todo esto funciona bien
Sin embargo, ahora estoy enfrentando un caso en el que necesito una instancia (por así decirlo) de una anotación. Entonces ... las anotaciones no son como las interfaces regulares y no se puede hacer una implementación anónima de una clase. Lo entiendo. He revisado algunas publicaciones aquí con respecto a problemas similares, pero parece que no puedo encontrar la respuesta a lo que estoy buscando.
Básicamente me gustaría obtener una instancia de una anotación y ser capaz de establecer algunos de sus campos usando la reflexión (supongo). ¿Hay alguna manera de hacer esto?
Bueno, aparentemente nada es tan complicado. ¡De Verdad!
Como señaló un colega, puede simplemente crear una instancia anónima de la anotación (como cualquier interfaz) como esta:
MyAnnotation:
public @interface MyAnnotation
{
String foo();
}
Invocar código:
class MyApp
{
MyAnnotation getInstanceOfAnnotation(final String foo)
{
MyAnnotation annotation = new MyAnnotation()
{
@Override
public String foo()
{
return foo;
}
@Override
public Class<? extends Annotation> annotationType()
{
return MyAnnotation.class;
}
};
return annotation;
}
}
Créditos a Martin Grigorov .
El enfoque de proxy, como se sugiere en la respuesta de Gunnar ya está implementado en GeAnTyRef :
Map<String, Object> annotationParameters = new HashMap<>();
annotationParameters.put("name", "someName");
MyAnnotation myAnnotation = TypeFactory.annotation(MyAnnotation.class, annotationParameters);
Esto producirá una anotación equivalente a lo que obtendrías de:
@MyAnnotation(name = "someName")
Las instancias de anotación producidas de esta manera actuarán de manera idéntica a las producidas por Java normalmente, y sus hashCode
y equals
se han implementado correctamente para la compatibilidad, por lo que no hay advertencias extrañas como la instanciación directa de la anotación como en la respuesta aceptada. De hecho, JDK usa internamente este mismo enfoque: sun.reflect.annotation.AnnotationParser#annotationForMap .
La biblioteca en sí misma es pequeña y no tiene dependencias.
Divulgación: soy el desarrollador detrás de GeAnTyRef.
Puede usar sun.reflect.annotation.AnnotationParser.annotationForMap(Class, Map)
:
public @interface MyAnnotation {
String foo();
}
public class MyApp {
public MyAnnotation getInstanceOfAnnotation(final String foo) {
MyAnnotation annotation = AnnotationParser.annotationForMap(
MyAnnotation.class, Collections.singletonMap("foo", "myFooResult"));
}
}
A la baja: las clases de sun.*
Están sujetas a cambios en las versiones posteriores (aunque este método existe desde Java 5 con la misma firma) y no están disponibles para todas las implementaciones de Java, consulte esta discusión .
Si eso es un problema: puede crear un proxy genérico con su propio InvocationHandler
: esto es exactamente lo que AnnotationParser
está haciendo por usted internamente. O utiliza su propia implementación de MyAnnotation
como se define here . En ambos casos, debe recordar implementar annotationType()
, equals()
y hashCode()
ya que el resultado está documentado específicamente para java.lang.Annotation
.