2009-02-23 4 views
9

Digamos que tiene dos instancias del mismo tipo de bean, y le gustaría mostrar un resumen de lo que ha cambiado entre las dos instancias; por ejemplo, tiene un bean que representa la configuración de un usuario en su aplicación, y usted ' Me gustaría poder mostrar una lista de lo que ha cambiado en la nueva configuración que el usuario está enviando (instancia n. ° 1) frente a lo que ya está almacenado para el usuario (instancia n. ° 2).Algoritmo común para generar un diff de los campos en dos beans?

¿Existe un algoritmo o patrón de diseño comúnmente utilizado para una tarea como esta, tal vez algo que pueda resumirse y reutilizarse para diferentes tipos de granos? (Estoy teniendo dificultades para pensar en un buen nombre para este tipo de problema para saber qué hacer con Google). He comprobado commons-beanutils y nada me ha salido.

Respuesta

6

Si está hablando de comparar valores, consideraría usar el reflejo y simplemente compararlos campo por campo.

Algo como esto:


    Field[] oldFields = oldInstance.class.getDeclaredFields(); 
    Field[] newFields = newInstance.class.getDeclaredFields(); 
    StringBuilder changes = new StringBuilder(); 

    Arrays.sort(oldFields); 
    Arrays.sort(newFields); 

    int i = 0; 
    for(Field f : oldFields) 
    { 
     if(!f.equals(newFields[i])) 
     { 
      changes.append(f.getName()).append(" has changed.\n"); 
     } 
     i++; 
    } 

Este código no ha sido probado. Puede que necesite obtener los valores en los campos y compararlos en lugar de simplemente comparar campos entre sí, pero debería funcionar en teoría.

+0

Existen algunos problemas con este código. Primero, asume que oldFields.length es lo mismo que newFields.length. Necesita un poco de lógica para determinar nuevos campos y campos que faltan. Finalmente, no usaría el bucle foreach cuando necesite incrementar un contador; solo usa un 'para'. –

+0

ambas son instancias de la misma clase exacta, ¿cómo puede ser diferente el número de campos? – kgrad

+0

Además, si se trata de un subproceso único, debe utilizar StringBuilder en lugar de StringBuffer. – cdmckay

2

El reflejo no mantiene el orden del campo en la próxima llamada: es más orden de las matrices.

/* 
*declarations of variables 
*/ 

Arrays.sort(oldFields);//natural order - choice 1 
Arrays.sort(newFields, new Ordinator());//custom Comparator - choice 2 

/* 
*logic of comparations between elements 
*/ 

En opción 2 se puede decidir la lógica de clasificación (COMO ORDENAR LOS ELEMENTOS) con una clase interna Ordinator extending Comparator.

PS el código es un proyecto de

3

Hemos hecho algo similar con utilidades de frijol y funcionó bien. Cosas a considerar: ¿Desglosa en objetos de campo? Si una Persona contiene una Dirección y la dirección cambia ¿dices que la dirección ha cambiado o esa dirección.Código postal ha cambiado (lo hacemos)? ¿Devuelve una lista de nombre de propiedad, valor antiguo, nuevo valor de la diferencia (lo hacemos)? ¿Cómo desea manejar las fechas? Si todo lo que le interesa es la parte de la fecha, ¿su comparación debe ignorar el tiempo? ¿Cómo se dice qué campos ignorar?

Esto no es realmente una respuesta de copiar y pegar, sino más de una lista de cosas que no eran inmediatamente obvias cuando escribimos nuestras diferencias.

En cuanto a la implementación, solo tenemos un método de utilidad estático que toma dos beans y una lista de propiedades para comparar y luego devuelve un mapa de propiedades a un par que contiene el valor anterior y el nuevo. Luego cada bean tiene un método diff(Object o) que llama al método de utilidad estática según sea necesario.

+0

Estoy trabajando en un requisito similar. La solución que describes parece interesante. ¿Sería capaz de compartir el código o los detalles del algoritmo? Gracias. – krishnakumarp

+1

Ojalá pudiera, pero fueron dos trabajos atrás. Sin embargo, escribí un código de muestra "inspirado en" para una entrevista hace dos años. No hace tanto como el original, pero puede ser útil para la inspiración. [Descárguelo] (http://stanford.edu/~pradtke/ObjectDiffer.zip) o [browse] (http://stanford.edu/~pradtke/ObjectDiffer/). – Patrick

1

Buenas respuestas arriba.

Si sus datos cambian estructuralmente, es decir, las colecciones completas de campos pueden ser relevantes o no depender de otras, es posible que desee considerar differential execution.

Básicamente, tiene un ciclo sobre los campos, y serializa los valores de campo actuales al mismo tiempo que deserializa los valores anteriores, comparándolos sobre la marcha.

Si hay una prueba condicional que hace que un bloque de campos sea relevante o no, se serializa/deserializa el valor verdadero o falso de la prueba condicional y se usa para decidir si serializar y/o deserializar los campos afectados Y se repite muy bien.

Solo una sugerencia.

+0

Gracias por el enlace, definitivamente voy a mirar esto –

3

Estas bibliotecas deberían ayudar.

https://code.google.com/p/beandiff/ - Una biblioteca de difracción de beans basada en anotaciones. Apache License 2.0

https://github.com/SQiShER/java-object-diff/ - Un bean se diferencia según el patrón Visitor. Apache License 2.0

Teníamos el requisito de generar diferencias entre los beans en formato json con fines de auditoría. Terminamos implementándolo usando la biblioteca beandiff.

** EDITAR ** Esto parece una opción más nueva. No lo he usado sin embargo.

http://beandiff.org/

espero que ayude.

0

Solución que utiliza reflexión y estructuras de datos estándar.

Field[] declaredFields = ClassOne.class.getDeclaredFields(); 
    Field[] declaredFields2 = ClassTwo.class.getDeclaredFields(); 
    ArrayList<String> one = new ArrayList<String>(); 
    ArrayList<String> two = new ArrayList<String>(); 
    for (Field field : declaredFields) 
    { 
     one.add(field.getName()); 
    } 

    for (Field field : declaredFields2) 
    { 
     two.add(field.getName()); 
    } 

    List<String> preone = (List<String>)one.clone(); 

    one.removeAll(two); 
    two.removeAll(preone); 
    Collections.sort(one); 
    Collections.sort(two); 

    System.out.println("fields only in One : " + one); 
    System.out.println("fields only in Two : " + two); 
Cuestiones relacionadas