//
you're reading...
General, Tips&Tricks

Using serialization to find dirty fields in an object

Say you are developing a framework to auto-save objects into a database. You need to detect changes made between two saves, so that only modified fields are saved. How to detect dirty fields. The easiest way to do this is to traverse through the original data and the current data and compare each field separately. Code as below:

    public static void getDirtyFields(Object obj, Object obj2, Class cls, Map<String, DiffFields> diff)
        throws Exception {
        Field[] flds = cls.getDeclaredFields();
        for (int i = 0; i < flds.length; i++) {
            flds[i].setAccessible(true);
            Object fobj = flds[i].get(obj);
            Object fobj2 = flds[i].get(obj2);
            if (fobj.equals(fobj2)) continue;

            if (checkPrimitive(flds[i].getType())) {
               <!-- add to dirty fields -->
                continue;
            }

            Map<String, DiffFields> fdiffs = new HashMap<String, DiffFields>();
            getDirtyFields(fobj, fobj2, fobj.getClass(), fdiffs);
            <!-- add to dirty fields -->
        }

        if (cls.getSuperclass() != null)
            getDirtyFields(obj, obj2, cls.getSuperclass(), diff);
    }

The above code does not handle a lot of conditions such as value of nulls, field being a collection or map or array etc. Yet, this gives an idea of what can be done. Works well if the object is small and does not contain a lot of hierarchy in them. When the change is very small in a huge hierarchical object, we have to traverse all the way to the last object to know the difference. Moreover, using equals may not be the right approach to detect dirty fields. Equals may not have been implemented, or simply it may just compare a few fields so a true dirty field detection is not done. You would have to traverse through each field irrespective of equals or not till you hit a primitive to detect dirty fields.

Here I want to talk of a different approach to detecting dirty fields. Instead of using reflection, we can use serialization to detect dirty fields. We can easily replace the “equals” in the above code to serialize the object and only if the bytes are different, continue further. But this is not optimal since we will be serializing the same object multiple times. We need a logic as below:

  • Serialize the two objects being compared
  • While comparing the two bytestreams, detect the fields being compared
  • If the byte values are different, store the field as different
  • Collect all the fields that are different and return them

Thus a single traversal of two byte streams can generate a list of fields that are different. How do we implement this logic? Can we traverse a serialized stream and be able to recognize fields in it? We want to write a code as below:

    public static void main(String[] args) throws Exception {
        ComplexTestObject obj = new ComplexTestObject();
        ComplexTestObject obj2 = new ComplexTestObject();
        obj2._simple._string = "changed";

        //serialize the first object and get the bytes
        ByteArrayOutputStream ostr = new ByteArrayOutputStream();
        CustomOutputStream str = new CustomOutputStream(ostr);
        str.writeObject(obj);
        str.close();
        byte[] bytes = ostr.toByteArray();

        //serialize the second object and get the bytes
        ostr = new ByteArrayOutputStream();
        str = new CustomOutputStream(ostr);
        str.writeObject(obj2);
        str.close();
        byte[] bytes1 = ostr.toByteArray();       

       //read and compare the bytes and get back a list of differing fields
        ReadSerializedStream check = new ReadSerializedStream(bytes, bytes1);
        Map diff = check.compare();
        System.out.println("Got difference: " + diff);
    }

The Map should contain _simple._string, so that we can directly go to _string and process it. In the next pages I explain how to do this.

About these ads

Discussion

No comments yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 144 other followers

%d bloggers like this: