7

Ejemplo de uso:
Quiero poner en los campos de clase una anotación personalizada @MyContainer y luego agregar automáticamente todas las anotaciones Hibernate relevantes de dichos campos (dependiendo del tipo de campo y las propiedades).
En adicional, necesito agregar la anotación JAXB XmlType a la clase y basar el nombre del tipo en el nombre de la clase.
Me gustaría añadir anotaciones adicionales a campos basados ​​en sus tipos, etc. Todas las anotaciones añadidas deberían estar disponibles en tiempo de ejecución (Así hibernate/JAXB puede encontrarlas).
Soy consciente de las siguientes opciones:Agregando anotaciones programáticas a una clase Java

  1. Pre-procesamiento fuente de la clase (mala opción)
  2. de procesamiento durante la compilación con las API javax.annotation.processing
  3. manipulación post recopilatorio con herramientas como Java Ayudar
  4. manipulación durante la carga de clases con las API java.lang.instrument
  5. hacerlo con AspectJ (no lo suficientemente potente)

Mis objetivos principales son:

  1. mantendrá siempre la sincronización entre la clase y la fuente para depurar
  2. de apoyo que trabajan tanto de Maven e IDE (Eclipse/IntelliJ)

Voy a apreciar si las personas que Ya hecho, tales cosas pueden recomendar el mejor enfoque para tal tarea (y quizás riesgos potenciales).

+0

¿Qué ocurre si no se generan anotaciones, sino que se generan archivos XML de asignación de hibernación (hbm.xml) que se pueden cargar mediante la configuración de hibernación? – Strelok

+0

Gracias, es una buena idea, pero prefiero la opción de anotación en mi caso ya que también necesito generar una anotación JAXB (y tal vez otras en el futuro). –

Respuesta

0

Creo que las fuentes de clases de preprocesamiento deberían ser su forma preferida. Esto le permite tener sus fuentes sincronizadas con las clases compiladas, lo cual es bueno para la depuración como mencionó. Pero también es bueno para el control de versiones, ya que puede verificar esas anotaciones generadas. También es mucho más difícil rastrear problemas en su herramienta, si se ejecuta durante la compilación. La compatibilidad con IDE tampoco debería ser un problema al ejecutar la generación de código en la fase de generación de fuentes.

Editar: búsqueda rápida produjo algunas informaciones sobre la modificación fuente de Java programática using the eclipse jdt o some thing in netbeans. Pero esto podría valer más investigación o una pregunta propia.

+0

Gracias por su respuesta. ¿Puede proporcionar más información sobre la solución, como qué herramienta se puede usar para analizar el código fuente y manipularlo? El inconveniente es que el código fuente se llena de anotaciones de bajo nivel y es menos claro (pensé en agregar la anotación solo para el tiempo de ejecución). –

+0

Si teme que esto pueda dar lugar a un código sucio, debe considerar usar una interfaz de su clase actual y ocultar la implementación con anotaciones tanto como sea posible. – SpaceTrucker

0

Quiero sugerir otro enfoque sobre eso. Como mi first answer podría implicar la codificación de una herramienta propia, también podría intentar una solución mucho más simple. Como espero que estés probando tus clases por unidades, podrías implementar una clase base para cada prueba unitaria de dicha clase. En esta clase base hay un método de prueba, que verifica que todos los campos anotados con @MyContainer también tengan las anotaciones de hibernación requeridas.

Básicamente hicimos lo mismo, no para anotaciones sino para la serialización de campos y funcionó bastante bien con ese enfoque.

0

Para que funcione de forma más transparente en IDE, compilación de línea de comando y en tiempo de ejecución, la opción 1 (usando APT) y la opción 5 (usando AspectJ) le darán mejor ajuste.

Para la opción 1, deberá implementar su propio procesador de anotación que inyectará anotaciones adicionales en función de la presencia de su propia anotación @MyContainer.Aquí hay un ejemplo de este enfoque utilizado para something similar.

Para la opción 5, simplemente puede usar annotation declaration. Algo como esto:

declare @field : * ((@*..MyContainer *)).*(..) : @OtherAnnotation(); 

herramienta Roo de la primavera está ampliamente utilizando la opción 5 y ciertamente no se puede decir que no es lo suficientemente potente.

+0

¿Puede basar las anotaciones y los parámetros de las anotaciones en la información de clase/método/miembro? Por ejemplo, necesito examinar el tipo de datos del contenedor y seleccionar entre algunas posibles anotaciones de hibernación. En adicional, necesito generar los nombres de las columnas para la anotación de hibernación en función de los nombres de los campos, etc. –

0

Hay pocas alternativas como se mencionó anteriormente y cada una tiene sus ventajas y desventajas. Es por eso que no creo que haya una verdadera respuesta "correcta" para la pregunta anterior. Mi propósito era obtener aportes de la comunidad y de personas que habían hecho esas cosas en el pasado y tenían experiencia. Personalmente, he elegido usar el Instrument API con Javassist. De esta forma, las clases se extienden en el tiempo de ejecución (aunque la misma herramienta se puede usar para el proceso de compilación posterior). Lo bueno es que el agente se puede cargar desde el interior de la JVM, lo que evita manejar todas las líneas de comando. Será genial escuchar otras alternativas.
Gracias,
Avner

0

Aquí está un ejemplo de código para definir la anotación personalizado. Este @TesterInfo se aplica a nivel de clase, almacena los detalles del probador. Esto muestra el uso diferente de los tipos de devolución: enumeración, matriz y cadena.

package com.mkyong.test.core; 

import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.TYPE) //on class level 
public @interface TesterInfo { 

    public enum Priority { 
     LOW, MEDIUM, HIGH 
    } 

    Priority priority() default Priority.MEDIUM; 

    String[] tags() default ""; 

    String createdBy() default "Mkyong"; 

    String lastModified() default "03/01/2014"; 

}