This week's giveaway is in the EJB and other Java EE Technologies forum.
We're giving away four copies of EJB 3 in Action and have Debu Panda, Reza Rahman, Ryan Cuprak, and Michael Remijan on-line!
See this thread for details.
The moose likes Java in General and the fly likes merging data values of two similar objects Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of EJB 3 in Action this week in the EJB and other Java EE Technologies forum!
JavaRanch » Java Forums » Java » Java in General
Bookmark "merging data values of two similar objects" Watch "merging data values of two similar objects" New topic
Author

merging data values of two similar objects

manish ahuja
Ranch Hand

Joined: Oct 23, 2003
Posts: 312
Hi there,

I would like to know your thoughts on this.

I have a scenario where in there is a custom java class with fair level of deep object graph. None of the attributes of this class are primitive data types.
For purpose of illustration I will provide a simplified scenario is like Class custom {BigDecimal a; String b; BigDecimal c; Boolean d;}

I have an instance of this class objOriginalCustom {a=10; b="Custom"; c=10.5; d=true;}
Also i get another instance of the same class objUpdateCustom { a="25";b='Update"}

Now what i want to do is modify the attributes of objOriginalCustom with the values of objUpdateCustom but only the ones for which i have valid values and retain the original data values if there are no replaceable values available in the objUpdteCustom (like c=10.5 and d=true) and replace a and b with values of 25 and "update"

Is there a convenient way to achieve the same in java or your thoughts on the approach to follow for the same.

Rgrds


Mark Vedder
Ranch Hand

Joined: Dec 17, 2003
Posts: 624

You could write a method that takes the update object, calls the getter for each property. If the value is not null, it calls the corresponding setter on the parent object with value from the update object. This method could be in your class directly, or in a utility class. The downside is that this method could get long, is a lot of redundant coding, and needs to be maintained as properties are added and subtracted from the target object.

If you wanted to "automate" this more, or make it generic so it can handle an object of any type, you could use reflection/introspection to get a list of all the settable properties. Then iterate through them calling the getter on the update object. (You'll likely want to make sure that the property is readable and writable.) If the value is not null, call the corresponding setter on the master object.

Take a look at the PropertyUtils class (and the PropertyUtilsBean class) in the Apache commons beanutils project. In particular look at the methods that deal with PropertyDescriptor objects. I think they would be helpful for you.
manish ahuja
Ranch Hand

Joined: Oct 23, 2003
Posts: 312
Thanks Mark. Your suggestions were helpful.

I could use the BeanUtils API classes PropertyUtils/PropertyDescriptors to achieve the same. I have a question on the same. Say if the object under consideration has a deep object graph like

class Custom {
AClass aObj; BClass bObj ; BigDecimal bd; String s; Integer i; Double d }

I am able to get the immediate attributes of the Custom class like String s, Integer i and Double d in the above scenario.

But how can i grab the attributes of AClass and BClass nested objects in a transparent manner. Is there a way I can introspect the Custom class and grab the attributes of the nested instances. Currently I retrieve these encompassing objects using the getters on the Custom class object where in the code is aware of the presence of these nested object type attributes. Subsequently I run the PropertyUtils/PropertyDescriptors code to retrieve the attributes of the nested objects.


Let me know your thoughts.


Regards.
Mark Vedder
Ranch Hand

Joined: Dec 17, 2003
Posts: 624

manish ahuja wrote:Thanks Mark. Your suggestions were helpful.
Say if the object under consideration has a deep object graph like

class Custom {
AClass aObj; BClass bObj ; BigDecimal bd; String s; Integer i; Double d }

I am able to get the immediate attributes of the Custom class like String s, Integer i and Double d in the above scenario.

But how can i grab the attributes of AClass and BClass nested objects in a transparent manner. Is there a way I can introspect the Custom class and grab the attributes of the nested instances.
Regards.


Do you need to clone the Custom object's properties upon updating?

In other words, lets say you have this:

When you update original with the values from updated, can original.aObj point to instance 2 of AClass? If so, all of aObj's attributes are the same. Of do you for some reason need to clone updated.aObj so that original.aObj points to a new instance, instance 3, of AClass with the same property values as instance 2 of that class? If you need to clone, what are the reasons for needing to do such? If you are trying to update original's values with those of updated, I would assume you want to point to the actual instances, not clone them.

manish ahuja
Ranch Hand

Joined: Oct 23, 2003
Posts: 312
Thanks Again, Mark.

No I don't want to clone nested objects nor want to modify the 'Custom Updated' //instance of 2. Custom updated is an input.

What i want is the data values of the attributes of aObj and bObj of instance2 (Custom Updated), check if they are available and only then update corresponding attributes of instance1 (Custom Original).
If these values are available in Custom updated, use them to modify similar attributes in Custom Original.
The functionality is such that we would never require to overwrite a complete aObj or bObj as the intent is only to grab difference in data values. If there is no difference the Custom updated instance will always have null values for the data attributes.

Currently I am doing it something like this
--------------
PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(customObj);

for (PropertyDescriptor pd : propertyDescriptors)
log.debug("Property Descriptor name is " + pd.getName());

--------------

Output: Property Descriptor name is aObj

but if change the parameter in the above method to pass the nested object like

PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(aObj);

I get the desired output
Property Descriptor name is firstName
Property Descriptor name is lastName
Property Descriptor name is age

Later on in the code i can sift through this collection something like PropertyUtils.getProperty(aObj, pd.getName()) , check nullness and carry out the required tasks.

My question is rather than passing the nested objects like aObj and bObj is there a way I can pass customObj and still get a reference to all the nested attributes inside aObj and bObj.


Thanks



Mark Vedder
Ranch Hand

Joined: Dec 17, 2003
Posts: 624

Just so we are clear on vocabulary and terminology, by 'attributes' in your statement update corresponding attributes, I assume you mean the Class's properties (a.k.a. instance variables)?

If I understand you correctly, you do not not necessarily want to update the master object's property with a new reference, but rather update that property's properties if they are different.

So if you started with this:


After updating you do not want to see this:


but rather want to see this:

such that original.aObj still points to instance A1 of AClass, but with updated properties. Is that correct?

If so, my questions would be:

1) How far down does it have to recurse? Just the one level? Or do you also only want to update the changed properties of say cObj and dObj? If you want to recurse, what will be the rule to stop its recursion?

2) Do want to do this for all types of properties for the Class (i.e. the Custom class)? Or just specific ones.

Here's what I had originally envisioned when I initially answered your post:



Since introspection can be expensive, and I suspect you will be calling this update method a lot, we can put in this simple optimization to only get the PropertyDescriptor array once for a class:



As a next step, we can break the method up into two parts:



That should allow you to put some logic in place to determine if you directly update the property via the updateProperty method, or if you recursively call the updateObject method on the property's object.

I would also improve the Exception handling so that the updateObject catches the various reflection exceptions and wraps them into a some type of application specific exception with a more meaningful message. And of course add Javadocs ;)

I'm by no means a reflection or introspection expert; so there may well be a better way of doing this type of thing.

Additionally, I'd ask about the overall architectural design. This seems to be getting complex rather fast. And potentially confusing. Is there possibly a different way to do these updates? Rather then getting a skeleton object with just the new values, is there not a way for what ever is supplying the new values to have the old values made available to it so it can supply a completely populated updated object and not one with just limited properties? Is there an alternative way to store this data rather than in the current objects that are being used? An in memory or embedded database (such as HSQLDB or Derby) perhaps. Databases lend themselves to the manipulation of data a little better than objects in some cases. Your solution might be the right one given the circumstances. But I always think its important to ask and ask again these types of questions throughout the design and development process.


[edit]Add new lines because text was too wide for screen. CR[/edit]
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 36452
    
  15
Beware of long lines in code; they can be awkward to read with left-to-right scrolling.

I think this question is too difficult for beginners: moving.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: merging data values of two similar objects
 
Similar Threads
To Nikhil Pendharkar for IBM 287
IBM 287 ICE TEST
287 Pre-assessment test questions - Please answer
long post IBM.158
To use or not to use custom tablemodel?