poner pintar font colorear color java code-generation cglib

java - pintar - ¿Existen alternativas al cglib?



poner color a un jlabel java (5)

Por curiosidad, ¿existen proyectos de código abierto (estables) para la generación de código Java en tiempo de ejecución que no sea cglib? ¿Y por qué debería usarlos?


ASM java-asm

CGLIB y casi todas las demás bibliotecas están construidas sobre ASM, que a su vez actúa en un nivel muy bajo. Para la mayoría de las personas, este es un JVMS de JVMS ya que debe entender el código de bytes y un poco de JVMS para usarlo correctamente. Pero dominar el ASM es ciertamente muy interesante. Sin embargo, tenga en cuenta que si bien hay una gran guía de ASM 4 , en alguna parte de la API, la documentación javadoc puede ser muy concisa si está presente, pero se está mejorando. Sigue de cerca las versiones de JVM para admitir nuevas funciones.

Sin embargo, si necesita un control total, ASM es su arma preferida.

Este proyecto ve actualizaciones regulares; en el momento de esta edición, la versión 5.0.4 se lanzó el 15 de mayo de 2015.

Byte Buddy byte-buddy Buddy

Byte Buddy es una biblioteca bastante nueva, pero proporciona cualquier funcionalidad que CGLIB o Javassist proporcione y mucho más. Byte Buddy se puede personalizar completamente hasta el nivel del código de byte y viene con un lenguaje expresivo de dominio específico que permite un código muy legible.

  • Admite todas las versiones de código de bytes de JVM, incluidos los cambios semánticos de Java 8 de algunos códigos de operación con respecto a los métodos predeterminados.
  • ByteBuddy no parece sufrir los inconvenientes de otras bibliotecas
  • Altamente configurable
  • Bastante rápido ( code benchmark )
  • Escriba API con fluidez segura
  • Escriba devoluciones de llamada seguras

    Los avisos de Javassist o el código de instrumentación personalizado se basan en un código en una String simple String lo que el control y la depuración son imposibles dentro de este código, mientras que ByteBuddy permite escribirlos con Java puro.

  • Anotación conducida (flexible)

    Las devoluciones de llamada del usuario se pueden configurar con anotaciones que permiten recibir los parámetros deseados en la devolución de llamada.

  • Disponible como agente

    El ingenioso creador de agentes permite que ByteBuddy se utilice como agente puro o como agente adjunto. Permite diferentes tipos.

  • Muy bien documentado
  • Muchos ejemplos
  • Código limpio, ~ 94% de cobertura de prueba
  • Soporte para Android DEX

Quizás el principal inconveniente es que la API es un poco detallada para un principiante, pero está diseñada como una API opt-in formada como un DSL de generación proxy; No hay magia o fallas cuestionables. Al manipular el código de bytes, es probablemente la opción más segura y más razonable. También con múltiples ejemplos y un gran tutorial, esto no es un problema real.

En octubre de 2015, estos proyectos recibieron el premio a la elección de Oracle Duke . En este momento solo alcanzó el hito 1.0.0 , que es todo un logro.

Tenga en cuenta que mockito reemplazó a CGLIB por Byte Buddy en la versión 2.1.0.

Javassist javassist

El javadoc de Javassist es mucho mejor que el de CGLIB. La API de ingeniería de clase está bien, pero Javassist tampoco es perfecto. En particular, el ProxyFactory que es el equivalente del Enhancer de CGLIB, también tiene algunos inconvenientes, solo para enumerar algunos:

  • El método de puente no es totalmente compatible (es decir, el que se genera para los tipos de retorno covariantes)
  • ClassloaderProvider es un campo estático en su lugar, entonces se aplica a todas las instancias dentro del mismo classloader
  • La denominación personalizada podría haber sido bienvenida (con cheques para frascos firmados)
  • No hay un punto de extensión y casi todos los métodos de interés son privados, lo cual es incómodo si queremos cambiar algún comportamiento.
  • Si bien Javassist ofrece soporte para los atributos de anotación en las clases, ProxyFactory no los admite.

En el lado orientado a aspectos, uno puede inyectar código en un proxy, pero este enfoque en Javassist es limitado y un poco propenso a errores:

  • El código de aspecto se escribe en una cadena Java simple que se compila en opcodes
  • sin verificación de tipo
  • no genéricos
  • no lambda
  • no auto- (des) boxeo

También se reconoce que Javassist es más lento que Cglib. Esto se debe principalmente a su enfoque de leer archivos de clase en lugar de leer clases cargadas como lo hace CGLIB. Y la implementation sí es difícil de leer para ser justos; Si uno requiere hacer cambios en el código de Javassist, hay muchas posibilidades de romper algo.

Javassist también sufrió de inactividad, su mudanza a github alrededor de 2013 parece haber sido útil, ya que muestra confirmaciones regulares y solicitudes de la comunidad.

Estas limitaciones siguen vigentes en la versión 3.17.1. La versión se ha trasladado a la versión 3.20.0, pero parece que Javassist aún puede tener problemas con el soporte de Java 8.

JiteScript

JiteScript parece una nueva pieza de DSL para ASM, esto se basa en la última versión de ASM (4.0). El código se ve limpio.

Pero el proyecto todavía está en su edad temprana, por lo que la API / comportamiento puede cambiar, además de que la documentación es grave. Y actualizaciones escasas si no abandonadas.

Proxetta jodd

Esta es una herramienta bastante nueva, pero ofrece la mejor API humana . Permite diferentes tipos de proxies, como proxies de subclase (enfoque cglib) o tejido o delegación.

Aunque, esta es bastante rara, no existe información si funciona bien. Hay muchos casos de esquina con los que lidiar cuando se trata de bytecode.

aspectj

AspectJ es una herramienta muy poderosa para la programación orientada a aspectos (solo). AspectJ manipula el código de bytes para lograr sus objetivos de tal manera que pueda alcanzar sus objetivos con él. Sin embargo, esto requiere manipulación en tiempo de compilación; Oferta de primavera de tejido en tiempo de carga a través de un agente desde la versión 2.5 , 4.1.x

CGLIB cglib

Una palabra sobre CGLIB que se ha actualizado desde que se hizo esa pregunta.

CGLIB es bastante rápido, es una de las razones principales por las que todavía existe, junto con el hecho de que CGLIB funcionó casi mejor que cualquier otra alternativa hasta ahora (2014-2015).

En general, las bibliotecas que permiten la reescritura de clases en tiempo de ejecución deben evitar cargar cualquier tipo antes de que se reescriba la clase correspondiente. Por lo tanto, no pueden hacer uso de la API de reflexión de Java que requiere que se cargue cualquier tipo utilizado en la reflexión. En su lugar, tienen que leer los archivos de clase a través de IO (que rompe el rendimiento). Esto hace que, por ejemplo, Javassist o Proxetta sean mucho más lentos que Cglib, que simplemente lee los métodos a través de la API de reflexión y los anula.

Sin embargo, CGLIB ya no está en desarrollo activo. Hubo lanzamientos recientes, pero muchos consideraron que esos cambios no eran significativos y la mayoría de las personas nunca se actualizaron a la versión 3, ya que CGLIB introdujo algunos errores graves en los últimos lanzamientos, lo que realmente no generó confianza. La versión 3.1 corrigió muchos de los problemas de la versión 3.0 (desde la versión 4.0.3 Spring framework vuelve a empaquetar la versión 3.1 ).

Además, el código fuente de CGLIB es de calidad bastante pobre , por lo que no vemos nuevos desarrolladores que se unan al proyecto CGLIB. Para obtener una impresión de la actividad de CGLIB, consulte su lista de correo .

Tenga en cuenta que después de una proposición en la lista de correo de Guice , CGLIB ahora está disponible en github para permitir que la comunidad ayude mejor al proyecto, parece estar funcionando (varias solicitudes de confirmación y extracción, ci, maven actualizado), pero la mayoría de las preocupaciones aún permanecen. .

En este momento, estamos trabajando en la versión 3.2.0, y están enfocando el esfuerzo en Java 8, pero hasta ahora los usuarios que desean ese soporte de Java 8 tienen que usar trucos en el momento de la compilación. Pero el progreso es muy lento.

Y todavía se sabe que CGLIB está plagado de pérdida de memoria de PermGen. Pero otros proyectos pueden no haber sido probados en batalla durante tantos años.

Procesamiento de annotation-processing tiempo Procesamiento de annotation-processing

Este no es el tiempo de ejecución, por supuesto, pero es una parte importante del ecosistema, y ​​la mayoría del uso de la generación de código no necesita creación en tiempo de ejecución.

Esto comenzó con Java 5 que venía con la herramienta de línea de comandos separada para procesar las anotaciones: apt , y el proceso de anotación a partir de Java 6 está integrado en el compilador de Java.

En algún momento se le pidió que pasara explícitamente el procesador, ahora con el enfoque ServiceLoader (solo agregue este archivo META-INF/services/javax.annotation.processing.Processor al META-INF/services/javax.annotation.processing.Processor ) el compilador puede detectar automáticamente el procesador de anotaciones.

Este enfoque en la generación de código también tiene inconvenientes ya que requiere mucho trabajo y comprensión del lenguaje Java, no de bytecode. Esta API es un poco incómoda, y como uno es un complemento en el compilador, se debe tener mucho cuidado de hacer de este código el mensaje de error más resistente y fácil de usar.

La mayor ventaja aquí es que evita otra dependencia en el tiempo de ejecución, puede evitar la pérdida de memoria del permgen. Y uno tiene el control total sobre el código generado.

Conclusión

En 2002 CGLIB definió un nuevo estándar para manipular el código de bytes con facilidad. Muchas herramientas y metodología (IC, cobertura, TDD, etc.) que tenemos hoy en día no estaban disponibles o no estaban maduras en ese momento. CGLIB logró ser relevante por más de una década; Ese es un logro bastante decente. Fue rápido y con una API fácil de usar que manipular códigos de operación directamente.

Definió nuevos estándares con respecto a la generación de código, pero hoy en día ya no lo es porque el entorno y los requisitos han cambiado, por lo que los estándares y los objetivos también.

La JVM cambió y cambiará en las versiones recientes y futuras de Java (7/8/9/10) (invokedynamic, métodos predeterminados, tipos de valor, etc.). ASM actualizó su API y sus componentes internos con regularidad para seguir estos cambios, pero CGLIB y otros aún no los han usado.

Si bien el procesamiento de anotaciones está ganando terreno, no es tan flexible como la generación en tiempo de ejecución.

A partir de 2015, Byte Buddy , aunque es bastante nuevo en la escena , ofrece los puntos de venta más atractivos para la generación en tiempo de ejecución. Una tasa de actualización decente, y el autor tiene un conocimiento íntimo de las funciones internas del código de byte de Java.


CGLIB fue diseñado e implementado hace más de diez años en la era AOP y ORM. Actualmente no veo razones para usarlo y ya no mantengo esta biblioteca (excepto las correcciones de errores para mis aplicaciones heredadas). En realidad, todos los casos de uso de CGLIB que he visto son anti patrones en la programación moderna. Debería ser trivial implementar la misma funcionalidad a través de cualquier lenguaje de script JVM, por ejemplo, groovy.



Prefiero ASM bruto, que creo que es utilizado por cglib de todos modos. Es de bajo nivel, pero la documentación es brillante , y una vez que te acostumbres, estarás volando.

Para responder a su segunda pregunta, debe usar la generación de código cuando sus reflejos y proxies dinámicos comienzan a sentirse un poco improvisados ​​y necesita una solución sólida como una roca. En el pasado, incluso he agregado un paso de generación de código en el proceso de compilación en Eclipse, que me permite recopilar informes de todo lo que sea y de forma efectiva.