2009-02-23 4 views
9

Supponiamo che ci siano due istanze dello stesso tipo di bean e che desideri visualizzare un riepilogo delle modifiche apportate tra le due istanze, ad esempio se hai un bean che rappresenta le impostazioni di un utente nella tua applicazione e tu? Mi piacerebbe essere in grado di visualizzare un elenco di ciò che è cambiato nelle nuove impostazioni che l'utente sta inviando (istanza # 1) rispetto a ciò che è già memorizzato per l'utente (istanza # 2).Algoritmo comune per generare un diff dei campi in due bean?

Esiste un algoritmo o un modello di progettazione comunemente utilizzato per un'attività come questa, forse qualcosa che può essere astratto e riutilizzato per diversi tipi di fagioli? (Sto avendo difficoltà a pensare a un buon nome per questo tipo di problema per sapere su Google cosa fare). Ho controllato i fagioli comuni e niente è saltato fuori da me.

risposta

6

Se si sta parlando di confrontare i valori, prenderei in considerazione l'uso della riflessione e il confronto tra loro campo per campo.

Qualcosa di simile a questo:


    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++; 
    } 

Questo codice non è stato testato. Potrebbe essere necessario ottenere i valori nei campi e confrontarli invece di confrontare i campi l'uno con l'altro, ma dovrebbe funzionare in teoria.

+0

Ci sono alcuni problemi con questo codice. Innanzitutto, presuppone che oldFields.length sia uguale a newFields.length. Hai bisogno di una logica per determinare nuovi campi e campi che mancano. Infine, non userei il ciclo foreach quando è necessario incrementare un contatore in ogni caso; basta usare un 'for'. –

+0

sono entrambe istanze della stessa identica classe, in che modo il loro numero di campi può essere diverso? – kgrad

+0

Inoltre, se questo è a thread singolo, dovresti usare StringBuilder invece di StringBuffer. – cdmckay

2

Il riflesso non mantiene l'ordine del campo nella prossima chiamata: è più sicuro ordinare gli array.

/* 
*declarations of variables 
*/ 

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

/* 
*logic of comparations between elements 
*/ 

Nel scelta 2 si può decidere la logica di selezione (COME ORDINAMENTO DEGLI ELEMENTI) con una classe interna Ordinator extending Comparator.

PS il codice è un progetto

3

Abbiamo fatto qualcosa di simile con utils di fagioli e ha funzionato bene. Cose da considerare: scorri in oggetti di campo: se una persona contiene un indirizzo e le modifiche di indirizzo, dici che l'indirizzo è cambiato o che indirizzo.postalCode è cambiato (lo facciamo)? Restituisci un nome di propety di lista, vecchio valore, nuovo valore dal diff (noi facciamo)? Come vuoi gestire le date: se tutto quello che ti interessa è la data, allora il tuo paragone dovrebbe ignorare il tempo? Come dici quali campi ignorare?

Questa non è veramente una copia e incolla risposta, ma più di una lista di cose che non erano immediatamente evidenti quando abbiamo scritto la nostra differenza.

Per quanto riguarda l'implementazione, abbiamo solo un metodo di utilizzo statico che prende due bean e un elenco di proprietà da confrontare e quindi restituisce una mappa di proprietà a una coppia contenente il vecchio valore e il nuovo valore. Quindi ciascun bean ha un metodo diff(Object o) che chiama il metodo di utilizzo statico in base alle esigenze.

+0

Sto lavorando su un requisito simile. La soluzione che hai delineato sembra interessante. Saresti in grado di condividere i dettagli del codice o dell'algoritmo? Grazie. – krishnakumarp

+1

Vorrei poterlo fare, ma erano due lavori fa. Comunque, ho scritto un codice di esempio "ispirato da" per un'intervista due anni fa. Non fa tanto quanto l'originale, ma può essere utile per l'ispirazione. [Scaricalo] (http://stanford.edu/~pradtke/ObjectDiffer.zip) o [browse] (http://stanford.edu/~pradtke/ObjectDiffer/). – Patrick

1

Buone risposte sopra.

Se i dati cambiano strutturalmente, ovvero intere raccolte di campi possono essere pertinenti o meno in base ad altre, è possibile considerare differential execution.

Fondamentalmente, si dispone di un ciclo sui campi e si serializzano i valori del campo corrente contemporaneamente alla deserializzazione dei valori precedenti, confrontandoli man mano che si procede.

Se è presente un test condizionale che rende rilevante o meno un blocco di campi, serializzare/deserializzare il valore true-or-false del test condizionale e utilizzarlo per decidere se serializzare e/o deserializzare o meno i campi interessati E ricorre piacevolmente.

Solo un suggerimento.

+0

Grazie per il link, esaminerò sicuramente questo aspetto –

3

Queste librerie dovrebbero aiutare.

https://code.google.com/p/beandiff/ - Una libreria di diffondere i bean basata su annotazione. Apache License 2.0

https://github.com/SQiShER/java-object-diff/ - Un bean diverso in base al pattern Visitor. Apache License 2.0

Avevamo l'obbligo di generare differenze tra i bean in formato json per scopi di controllo. Abbiamo finito per implementarlo usando la libreria beandiff.

** MODIFICA ** Questa sembra una nuova opzione. Non l'ho usato comunque.

http://beandiff.org/

Speranza che aiuta.

0

Soluzione che utilizza la riflessione e le strutture dati standard.

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); 
Problemi correlati