with stored query nativas namednativequery createnativequery create consultas java annotations

java - stored - native query hibernate



Casos de uso para implementar anotaciones (4)

¿Cuáles son los casos de uso válidos para implementar anotaciones?

Al diseñar principalmente sistemas de configuración basados ​​en anotaciones, ocasionalmente necesito crear clases que implementen anotaciones para la generación de código o la configuración programática.

La alternativa implica reflejar los datos contenidos en las anotaciones en DTO, lo que parece una sobrecarga.

Aquí hay un ejemplo:

public enum IDType { LOCAL, URI, RESOURCE; } @Documented @Target( { METHOD, FIELD }) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface Id { /** * @return */ IDType value() default IDType.LOCAL; }

con la implementación

public class IdImpl implements Id{ private final IDType idType; public IdImpl(IDType idType){ this.idType = idType; } @Override public IDType value() { return idType; } @Override public Class<? extends Annotation> annotationType() { return Id.class; } }

Recibo advertencias de compilación para esto, pero parece ser una herramienta válida para muchos casos de uso.

La advertencia para el ejemplo anterior es

El Id del tipo de anotación no se debe usar como una superinterfaz para IdImpl

Editado:

Acabo de encontrar este ejemplo de Guice :

bind(CreditCardProcessor.class) .annotatedWith(Names.named("Checkout")) .to(CheckoutCreditCardProcessor.class);

Vea este Javadoc de Names .

¿Alguien tiene alguna información sobre por qué existe esta restricción o tiene otros casos de uso en mente?


Lo uso cuando creé una anotación y deseo hacer que su uso sea opcional, proporcionando un valor predeterminado.

Para usar tu ejemplo; Cuando proceso / introspejo los siguientes beans, quiero usar un valor predeterminado para BeanB .

@Id class BeanA {} // No annotation class BeanB {}

La implementación predeterminada;

private static final Id DEFAULT_ID = new Id() { @Override public IDType value() { return IDType.LOCAL; } @Override public Class<? extends Annotation> annotationType() { return Id.class; } };

Tratamiento;

Id beanId = (bean.getClass().isAnnotationPresent(Id.class)) ? bean.getClass().getAnnotation(Id.class) : DEFAULT_ID;


No hay casos de usuario válidos para eso, el compilador simplemente lo tolera, ya que sería bastante complicado prohibirlo y las personas que escriben compiladores pueden necesitar el servicio en muy raras ocasiones. Si necesita clasificar las anotaciones, consulte este artículo para ver cómo hacerlo: ¿Por qué no es posible extender las anotaciones en Java?

Inocular un alma pobre que viene detrás de ti para mantener y depurar ese código u otro que necesite escribir una herramienta Codegen y asume que los tipos de anotación son rectas u otro que acaba de usar dicha anotación sin siquiera soñar qué puede suceder y qué hacer al respecto. Para cuando descubra ese truco y encuentre la manera de eliminarlo, va a morir de hernia, o dolencia equivalente :-) Se espera que las anotaciones sean declaraciones puramente declarativas, interpretadas únicamente por una herramienta Codegen que se ejecuta por separado del código anotado y lo trata como datos.

Eche un vistazo fresco a ese código y trate de decir honestamente qué es un rasón racional para algo como:

public Class<? extends Annotation> annotationType() { return Id.class; }

y aún es una pequeña cosa en comparación con la gente que puede poner en el código.

Las anotaciones no son el lugar para practicar la piratería, eso es lo que el compilador intenta transmitir. ¿Sabes exactamente cuándo y cómo se puede ejecutar el código en la "implementación" de la anotación? Incluyendo CTOR? ¿Qué está disponible y qué no en ese punto? ¿Qué es seguro llamar? El compilador no lo hace: se necesitaría un análisis estático bastante pesado para que un compilador verifique la seguridad real de tal pirateo. Por lo tanto, en su lugar solo emite una advertencia para que cuando algo sale mal, la gente no pueda culpar a la compilación, VM y todo lo demás.


Nunca lo he usado en la práctica pero lo que obtienes es que puedes usar clases como reemplazo para tus anotaciones.

Vamos a crear un ejemplo artificial. Digamos que tenemos un generador de documentación. Lee una anotación @Docu de clases dadas e imprime el atributo de description . Me gusta esto:

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.ArrayList; import java.util.List; public class DokuGenerator { public static void main(String[] args) throws Exception { new DokuGenerator(StaticClass.class, StaticClass2.class); } public DokuGenerator(Class<?>... classesToDokument) throws Exception { List<Docu> documentAnnotations = getDocumentAnnotations(classesToDokument); printDocumentation(documentAnnotations); } private List<Docu> getDocumentAnnotations(Class<?>... classesToDokument) throws Exception { List<Docu> result = new ArrayList<Docu>(); for (Class<?> c : classesToDokument) if (c.isAnnotationPresent(Docu.class)) result.add(c.getAnnotation(Docu.class)); return result; } private void printDocumentation(List<Docu> toDocument) { for (Docu m : toDocument) System.out.println(m.description()); } } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface Docu { String description(); } @Docu(description = "This is a static class!") class StaticClass { } @Docu(description = "This is another static class!") class StaticClass2 { }

Huellas dactilares:

This is a static class! This is another static class!

Lo que ahora queremos lograr es que una clase no solo tenga anotaciones estáticas, sino que también pueda agregar información de tiempo de ejecución a la documentación. Estamos muy contentos de utilizar la anotación @Docu mayor parte del tiempo, pero hay casos especiales en los que queremos una documentación especial. Es posible que deseemos agregar documentacion de rendimiento para algunos metodos. Podemos hacer esto permitiendo que una clase implemente la anotación. El generador verifica primero la anotación y, si no está presente, verifica si la clase implementa la anotación. Si lo hace, agrega la clase a la lista de anotaciones.

Me gusta esto (solo dos líneas adicionales de código en el generador):

import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class DokuGenerator { public static void main(String[] args) throws Exception { new DokuGenerator(StaticClass.class, StaticClass2.class, DynamicClass.class); } public DokuGenerator(Class<?>... classesToDokument) throws Exception { List<Docu> documentAnnotations = getDocumentAnnotations(classesToDokument); printDocumentation(documentAnnotations); } private List<Docu> getDocumentAnnotations(Class<?>... classesToDokument) throws Exception { List<Docu> result = new ArrayList<Docu>(); for (Class<?> c : classesToDokument) if (c.isAnnotationPresent(Docu.class)) result.add(c.getAnnotation(Docu.class)); else if (Arrays.asList(c.getInterfaces()).contains(Docu.class)) result.add((Docu) c.newInstance()); return result; } private void printDocumentation(List<Docu> toDocument) { for (Docu m : toDocument) System.out.println(m.description()); } } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface Docu { String description(); } @Docu(description = "This is a static class!") class StaticClass { } @Docu(description = "This is another static class!") class StaticClass2 { } class DynamicClass implements Docu { public DynamicClass() { try { Thread.sleep((long) (Math.random() * 100)); } catch (InterruptedException e) { // ignore exception to make debugging a little harder } } @Override public String description() { long millis = System.currentTimeMillis(); new DynamicClass(); millis = System.currentTimeMillis() - millis; return "This is a dynamic class. I run on " + System.getProperty("os.name") + ". The construction of an instance of this class run for " + millis + " milliseconds."; } @Override public Class<? extends Annotation> annotationType() { return Docu.class; } }

La salida es:

This is a static class! This is another static class! This is a dynamic class. I run on Windows XP. The construction of an instance of this class run for 47 milliseconds.

No debe cambiar mucho el generador de códigos porque puede usar la clase como reemplazo de la anotación.

Otro ejemplo sería un marco que usa anotaciones o XML como configuración. Es posible que tenga un procesador que funcione con anotaciones. Si usa XML como configuración, puede generar instancias de clases que implementen las anotaciones y su procesador trabaje en ellas sin un solo cambio. (por supuesto, hay otras formas de lograr el mismo efecto, pero esta es UNA forma de hacerlo)


JAXBIntroductions es un buen ejemplo: permite configurar anotaciones JAXB utilizando archivos XML. Me vienen a la mente dos casos de uso principales: configuración de clases en las que no tienes acceso de fuente o diferentes configuraciones para una clase.

En general, creo que crear instancias de anotaciones dinámicamente para pasarlas a frameworks es generalmente un buen caso de uso. Sin embargo, si usted es el diseñador de este marco, sin duda lo pensaría dos veces.