2010-02-22 6 views
5

Hola, oyente por primera vez oyente por primera vez, y estoy haciendo una pregunta relacionada con la reflexión de Java, y qué fácil se presta a una codificación aparentemente desagradable. El siguiente método intenta tomar dos objetos similares (un objeto que tiene todos los campos del otro objeto, y algunos) y compararlos para la igualdad. Será (supuestamente) devuelto verdadero si los captadores que los objetos comparten son iguales, y devolverá falso si no son iguales.Uso eficaz de la reflexión de Java: ¿se trata de un truco, o es esta práctica estándar?

public boolean validateArchive(Object record, Object arcRecord) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException 
{ 
    log.debug(record.getClass().toString()); 

    Object methodValue; 
    Object arcMethodValue; 

    for (Method method : record.getClass().getMethods()) 
    { 
     if (method.getTypeParameters().length == 0 && method.getName().startsWith("get") && !method.getName().startsWith("getClass")) 
     { 
      methodValue = method.invoke(record); 
      arcMethodValue = arcRecord.getClass().getMethod(method.getName()).invoke(arcRecord); 

      log.debug("Method name: " + method.getName()); 
      log.debug("Archive value: " + arcMethodValue); 
      log.debug("Object value: " + methodValue); 

      if (arcMethodValue != null && methodValue != null && !arcMethodValue.equals(methodValue)) 
      { 
       return false; 
      } 
      else 
      { 
       if (arcMethodValue == null && methodValue != null || methodValue == null && arcMethodValue != null) 
       { 
        return false; 
       } 
      } 
     } 
    } 

    return true; 
} 

Este método hace lo que se espera que haga en las pruebas de unidad, pero se ve feo, y se siente mal (yo particularmente no soy un fan de la anidada 'si'). Solo esperaba algunos consejos sobre cómo hacer esto de manera más efectiva/eficiente. Si he roto algún tipo de regla de publicación, no dude en corregirme, estoy ansioso por aprender, etc.

+0

Primera observación: ni siquiera comprueba si los dos objetos son de la misma clase. Su arcMethod bien podría estar ausente de su objeto de archivo. –

+0

No se supone que sean de la misma clase, pero supongo que supongo que el usuario del método es lo suficientemente inteligente como para pasar dos objetos similares (la entidad en sí, y luego la entidad de archivo de ese mismo objeto es el uso previsto) . Lo que podría hacer es validar que los dos objetos son de hecho objeto + archivo de objeto comparando nombres de clase, pero que se siente aún más pirateado. Quizás no lo sea. –

Respuesta

6

Para esta tarea en particular, recomendaría implementar el método equals en las clases que se compararán, a menos que no tiene esa opción (por ejemplo, si no tiene el código fuente para la clase original). Los IDE's como IntelliJ proporcionan soporte para la creación de métodos "iguales" y "código hash" (en IntelliJ, usted proporciona los campos que se compararán y los campos que pueden ser nulos o no). Para este caso particular, diría que vaya con estas herramientas.

Hay un caso en el que creo que sería útil una implementación usando Reflection: en una prueba unitaria, si desea lanzar un error de aserción si la igualdad no es verdadera, puede lanzar una afirmación para el campo exacto que está fallando, y no solo un error de aserción genérico de "objeto no es lo mismo" - incluso en este caso, realizaría un igual a después de mi validación original solo para asegurarme de que los objetos son los mismos, o al menos eso el método equals está implementado y funciona correctamente.

PD: Si quiere deshacerse de todo este código, consulte la biblioteca Beans Common; PD 2: La reflexión no está mal, y se usa en todas partes donde no tiene una llamada de código explícita - Archivos de configuración de Spring, por ejemplo. Simplemente no lo abuse.

+0

No tengo control sobre ninguna de las clases originales en esta situación (son generadas por iBator/iBatis, si tiene curiosidad por qué), y es por eso que no he hecho simplemente una hereda de la otra, de lo contrario tendría , limpiando esto un poco. Ninguno de los objetos esperados tendrá ningún método igual significativo disponible, desafortunadamente. –

+0

Siento que lo que estoy haciendo es un poco ofensivo para Reflection, realmente no puedo pensar en una mejor manera de hacer esta tarea. Los objetos que se pasan pueden tener cualquier número de campos, y no sé qué son, solo que tendrán getters para cada uno, y que el objeto arcRecord siempre tendrá los mismos getters que el objeto primario. –

2

Como usted está buscando sólo para "propiedades" que podrían usar commons beanutils y más precisamente this class ...

(supongo que no se puede poner en práctica .equals porque sus objetos no comparten el mismo tipo ...)

+0

Eso simplemente envuelve la fealdad detrás de otra API. Toda esa basura de reflexión todavía está allí, está escondida detrás de una biblioteca. – KitsuneYMG

1

creo que está probando para los casos innecesarios en sus declaraciones if, y puede reducirlas a esto:

if (arcMethodValue == null) { 
    if (methodValue != null) { 
     return false; 
    } 
} else if (!arcMethodValue.equals(methodValue)) { 
    return false; 
} 

también, que está llamando method.getName() 4 veces, puede crear una variable y luego usarlo.

+0

Excelente, gracias por los consejos. –

+0

Vea mi respuesta para una mejor expresión idiomática. – polygenelubricants

+0

@polygene: su respuesta es incorrecta. – JRL

0

Su código de retorno es innecesariamente complicado. El lenguaje estándar para la comparación de los tipos de referencia es la siguiente:

(field1 == null) ? (field2 == null) : field1.equals(field2); 

Esto es mucho más claro y es bastante estándar (Java eficaz segunda edición, página 43).


Actualización:

Hubo una confusión, ya que anteriormente había escrito return [idiom]. Sí, en este caso, un return no sería lo que desea el póster original.Él querría en su lugar. Mi punto es que el [idiom] funciona, y es mucho mejor.

+0

Gracias por esto, sabía que estaba siendo demasiado complejo con eso. –

+0

En una inspección posterior, el problema con esto es que, en el lugar donde se encuentra el anidado, nunca debe volverse verdadero, donde esto volverá verdadero si el campo2 es nulo pero el campo1 no, lo cual es malo. –

+0

Entonces, en lugar de 'return [idioma];', haces 'if! [Idioma] return false;'. Solo estaba compartiendo el modismo, sin pedirte que lo pusieras allí como está (por eso cambié el nombre de las cosas). He editado el retorno de la respuesta para que esto sea aún más claro. – polygenelubricants

Cuestiones relacionadas