2009-06-22 13 views
10

La reflexión de Java proporciona un mecanismo para introspectar un objeto en tiempo de ejecución. Sin dudas, esta es una gran característica, ¡pero rompe todas las convenciones de refactorización!Reflexión de Java y el dolor en la refactorización

No hay una manera fácil (que no sea File Search) incluso en los IDE modernos de saber a qué atributo se hace referencia y dónde. Esto hace que las Refacciones sean mucho más complejas (¡tediosas!) Y propensas a errores.

Para ser sincero, no es solo el Reflection API; Hibernate mapping files (hbm.xml) y JSP files ambos se refieren a los atributos como Cadena y cuando refactoriza su nombre de atributo, entonces tiene que cambiar manualmente en todos estos lugares.

Peor aún, los cambios en los archivos de mapeo de Hibernate o en los archivos JSP producen errores en el tiempo de ejecución.

Estoy interesado en saber cómo otros programadores manejan esto en Java. ¿Hay algunas herramientas? Uso Eclipse/IBM RAD como plataforma de desarrollo principal. Normalmente usamos un constant para definir el atributo y usarlo siempre que sea posible, pero no siempre es posible.

¡También me interesaría saber cómo otros idiomas manejan esto!

+1

IntelliJ tiene muy buenos anzuelos en los archivos de configuración JSP, Spring e Hibernate en estos días, todos los cuales son 'refactorizados'. No soy un usuario de Eclipse, pero pensé que también tenía algo similar. –

+0

también netbeans tiene algunas herramientas inteligentes de refactorización (primavera, web.xml, etc.) – dfa

+0

Creo que Eclipse también puede refactorizar a través de los archivos de Hibernate. –

Respuesta

7

La reflexión de Java causa muchos de los mismos problemas que se obtienen con los lenguajes de tipado dinámico como Python y Ruby. De hecho, una forma de pensar sobre los lenguajes de tipado dinámico es que todo se llama mediante el uso de la reflexión, y los lenguajes solo proporcionan una sintaxis limpia y agradable para la reflexión.

Y sí, con los idiomas dinámicos (o los usos intensos de la reflexión), la refacturación es difícil. No obtiene las buenas capacidades de refactorización de Eclipse. En cambio, grep se convierte en tu amigo.

Desde mi experiencia, lo mejor que puede hacer es construirse una buena red de seguridad de pruebas unitarias. De esta forma, si rompe un código dinámico durante la refactorización, al menos lo detectará rápidamente cuando ejecute las pruebas.

Si está haciendo un montón de código estáticamente tipado, está en un gran problema si no tiene una buena base de pruebas de unidad. Si está haciendo un montón de código de tipo dinámico (incluido un código con muchas reflexiones), no tiene ninguna esperanza de tener éxito sin una buena base de pruebas unitarias.

+0

En realidad, el primer IDE que implementó la refactorización fue Smalltalk, que es bastante dinámico. AFAIK la herramienta de refactorización hizo el análisis al monitorear el código tal como se ejecutó (generalmente a través de pruebas unitarias) y ver qué rutas se usan, a qué métodos se llama, etc. Es posible refactorizar el código dinámico, pero es difícil de implementar y creo esa es la razón por la que no está ampliamente disponible en IDE. – gooli

2

IDE modernos tienen la característica de que al cambiar el nombre de una clase, buscarán el nombre completo en, por ejemplo, sus archivos xml para tratar de cambiar el nombre de las referencias que pueda tener en esos. No crea que resuelve el problema: muy a menudo no hace referencia absoluta a nombres de clase.

Además, es por eso que se debe tener especial cuidado y consideración antes de usarlo en su propio código.

Pero este problema con la reflexión es por qué el uso de anotaciones es cada vez más popular. El problema se reduce cuando se usan anotaciones.

Pero permítanme decir, como señala correctamente la publicación anterior, si no tiene una buena red de seguridad de pruebas unitarias, cualquier tipo de refactorización, ya sea que use mucha reflexión o no, es peligroso.

+0

¿Cómo soluciona la anotación el problema en tales escenarios? ¿Puede dar un ejemplo? Gracias. – lud0h

+0

Es en términos de persistencia, por ejemplo. Si utilizo anotaciones para especificar que una clase es persistente, por ejemplo, y cambio el nombre de esa clase, la anotación se mantendrá y seguirá siendo persistente. No tendré que ir y encontrar todas las instancias en las que la clase hace referencia en los archivos de mapeo y cambiar eso también. –

0

Puede que le interese usar IntelliJ IDEA, que también buscará los nombres de clase refactorizados en comentarios y constantes de cadena.

+0

netbeans (y problably otros) también – dfa

+1

Eclipse (y presumiblemente netbeans) pueden hacer eso también, pero no está garantizado que funcione, ya que solo detectará nombres de clase totalmente calificados –

0

Bueno, es otra oportunidad para que IDE venda costosas versiones premium que reconocerán y refaccionarán nombres de clase utilizados en archivos de configuración específicos.

Alternativamente, estos casos recurrentes pueden ser manejados por un conjunto de pruebas que realiza la comprobación de cordura en tales archivos, es decir, verifica que existan todas las clases y métodos referidos. Tales son específicos para un formato de archivo, pero a menudo son relativamente fáciles de escribir y luego se pueden usar para verificar todos los archivos de ese formato.

Pero no hay una solución general para el uso directo y "manual" de la API de reflexión, por lo que generalmente no se recomienda.

+0

El problema no es solo con la API de Reflection. Los archivos de configuración como en Hibernate o JSP tienen un límite de tiempo de compilación y las herramientas no los capturan de manera efectiva. – lud0h

+0

Dado que esos archivos tienen una sintaxis bien definida, al menos es posible (y no demasiado difícil). –

1

La refabricación podría mejorarse introduciendo más "literales" en el idioma. P.ej. imho .class literal es una gran manera de garantizar la seguridad en tiempo de compilación de ciertos modelos. Sin embargo, lo importante de decir aquí es que, a veces, Quiero perder seguridad en tiempo de compilación. Las cadenas son la forma más simple pero poderosa de expresar un contrato débilmente acoplado entre dos capas, ya que puedes manipularlas o unirlas a una expresión regular, etc.

El problema real de la reflexión es el uso detallado de la API. El es el mayor costo de flexibilidad.

PS

moneda proyecto podría introducir algún lugar en el futuro alguna nueva construcción del lenguaje para mejorar esta área.

0

Como un aparte, Reflection también causa problemas si desea proteger su código a través de ofuscación. Las herramientas de ofuscación típicas ahora requieren que mantenga una lista de todos los archivos que no quiere que se ofusquen para que la reflexión de todos los archivos de configuración XML funcione correctamente.

Dicho esto, una versión J2EE de Eclipse IDE junto con los complementos adecuados para los principales frameworks como Hibernate, Spring, etc. harán un trabajo bastante bueno al manejar la refactorización. Las pruebas unitarias reducirán el ciclo de prueba, pero la preocupación es que a veces las pruebas unitarias también dependen de alguna configuración XML que lo obligue a usar la reflexión. Por lo tanto, es posible romper las pruebas unitarias junto con su código mientras se refactoriza.

0

¿Qué pasa con las clases de taggin, los métodos, los campos que conoce a los que se accede por reflexión? El IDE podría advertirte cuando cambies sus nombres.

0

Puede evitar escribir API de reflexión con dp4j.com cuando sepa en tiempo de compilación lo que está buscando.

Acerca de las asignaciones de xml, son un problema, también experimenté con NetBeans Platform y menos con JPA2. La buena noticia es que las anotaciones se están haciendo cargo, y esto ofrece una nueva verificación en tiempo de compilación. No estoy seguro acerca de Hibernate, pero tanto JPA como NetBeans (more as of 7) ofrecen anotaciones equivalentes de asignaciones de xml.

También había desarrollado SqlWrapper para evitar el uso de cadenas con JDBC. Más sofisticada (y complicada) es la API de criterios de JPA2.

Cuestiones relacionadas