Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Common algorithm for generating a diff of the fields in two beans?

Let's say you have two instances of the same bean type, and you'd like to display a summary of what has changed between the two instances - for example, you have a bean representing a user's settings in your application, and you'd like to be able to display a list of what has changed in the new settings the user is submitting (instance #1) versus what is stored already for the user (instance #2).

Is there a commonly used algorithm or design pattern for a task such as this, perhaps something that can be abstracted and re-used for different types of beans? (I'm having a hard time thinking of a good name for this type of problem to know what to Google on). I've checked commons-beanutils and nothing popped out at me.

like image 516
matt b Avatar asked Feb 23 '09 16:02

matt b


4 Answers

If you are talking about comparing values, I would consider using reflection and just comparing them field by field.

Something like this:


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

This code hasn't been tested. You might need to get the values in the fields and compare them instead of just comparing fields to each other, but it should work in theory.

like image 132
kgrad Avatar answered Nov 20 '22 01:11

kgrad


The reflection not mantains the order of the Field in next calling: it's safier order the arrays.

/*
*declarations of variables
*/

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

/*
*logic of comparations between elements
*/

In choice 2 you can decide the logic of sorting (HOW SORTING THE ELEMENTS) with an inner class Ordinator extending Comparator.

PS the code is a draft

like image 34
alepuzio Avatar answered Nov 20 '22 02:11

alepuzio


We've done something similar with bean utils and it worked well. Things to consider: Do you drill down into field objects - If a Person contains an Address and the address changes do you say the address changed or that address.postalCode changed(we do)? Do you return a list propety name, old value, new value from the diff (we do)? How do you want to handle dates - if all you care about is date part then your comparison should ignore the time? How do you say which fields to ignore?

This isn't really a copy and paste answer but more of list of things that weren't immediately obvious when we wrote our differ.

As for implementation, we just have a static util method that takes two beans and a list of properties to compare and then returns a map of properties to a Pair containing the old value and the new value. Then each bean has a diff(Object o) method that calls the static util method as needed.

like image 3
Patrick Avatar answered Nov 20 '22 03:11

Patrick


These libraries should help.

https://code.google.com/p/beandiff/ - An annotation based bean diffing library. Apache License 2.0

https://github.com/SQiShER/java-object-diff/ - A bean differ based on Visitor pattern. Apache License 2.0

We had a requirement to generate difference between beans in json format for auditing purpose. We ended up implementing it using beandiff library.

** EDIT ** This looks like a newer option. I have not used it though.

http://beandiff.org/

Hope it helps.

like image 3
krishnakumarp Avatar answered Nov 20 '22 03:11

krishnakumarp