views:

6890

answers:

6

If I have a form-backing object that has a complicated object tree -- say a Person that has a Contact Info object that has an Address object that has a bunch of Strings -- it seems that the object needs to be fully populated with component objects before I can bind to it. So if I'm creating a new Person, I need to make sure it has all the component objects populated off the bat, and if I'm retrieving a Person from the database, I need to make sure that any objects that aren't populated from the database get populated with empty objects.

First question, of course -- am I correct in my assumptions above? It does seem that if I try to bind to person.contactInfo.homeAddress.street and there is no ContactInfo, I get a null pointer exception.

Second, what's the best way to initialize my object. I can think of a couple of approaches. One is to initialize all member objects at declaration:

public class Person {
     String name;
     ContactInfo contactInfo = new ContactInfo();
     //getters, setters, etc.
}

public class ContactInfo {
     String phone;
     Address homeAddress = new Address();
}

and so forth.

Another approach is to have a PersonFactory that initializes everything (or to have a factory method Person.getInstance that initializes everything).

In the case of retrieving a Person from the database, the first approach will solve the issue (i.e. if this particular person doesn't have an address in the database, the object will still have an Address), but this will mean creating each object twice. Not sure how to handle this otherwise, except to make the DAO explicitly populate everything even if nothing has been retrieved from the database. Or to give the factory a method to go through the object and "fill in" anything that's missing.

Suggestions?

A: 

I guess you are talking about something like < form:input path="person.contactInfo.homeAddress.street"/> ? Not clear for me but assuming i'm right :) :

1) Yes, When you write person.contactInfo.homeAddress.street , read person.getContactInfo().getHomeAddress().getStreet(). If ContactInfo or HomeAddress or Street objects are null, invocation of one of their method raises a NullPointException.

2)I usually initializes member objects at declaration, just like in code snippet. Don't see the benefit of factory class to do the job if initialization values are inconditionnal. I don't clearly see the problem where you are forced to create a Person twice... but i may be tired ;)

Olivier
If I'm retrieving stuff from the database, then the initialization at declaration will create a ContactInfo, which will then be replaced by another ContactInfo created by the DAO with data in it. So I'll have created an extra one.
JacobM
+1  A: 

I would generally make sure objects are fully initialized - it makes using the object that much simplier and avoids you scattering null checks throughout your code.

In the case you give here I'd probably put the initialization in the getter so the child object is only instantiated when it's actually going to be used, ie: when the getter is called and then only if it's null.

In terms of loading from the database with one-to-one relationships I'd normally do the join and load the lot. The performance impact is typically minimal but you should be aware that there may be one.

When it comes to one-to-many relationships I normally go for lazy loading. Hibernate will take of this for you, but if you're rolling your own then you just need a custom implementation of List that calls the appropriate DAO when any of the methods relating to its contents are called.

The one exception to this behavior with one-to-many relationships is when you've got a list of parent objects that you intend to iterate over and for each parent you want to iterate over its children. Obviously the performance would suck because you'd be making a n + 1 calls to the DB when you could actually do it with 2 calls.

Nick Holt
Thanks. I like the idea of putting the initialization in the getter; best of both worlds for me. I'll try it out and mark this as the "answer" if it seems to be working out.For collections I like to use LazyList from Apache Commons. It allows you to specify a factory.
JacobM
Addendum to the LazyList point -- it turns out that Spring has a lazy list itself called AutoPopulatingList.
JacobM
+1  A: 

I've gone with the Factory method approach (not a fan of using a seperate class for it, to me it makes more sense to have it in a static method so it's all in one place). I have something like -

public static Person getInstanceForContactInfoForm() {
      ContactInfo contactInfo = ContactInfo.getInstanceForContactInfoForm();

      Person person = new Person(contactInfo);
      // set whatever other properties you need for Person
      // just enough to 1-render the form and 2-avoid any exceptions
      return person;
}

If I'm loading the Person from the database, I have a method in the Person class called something like "initalizeForContactInfoForm" or something. After loading the Person from the database, I'll call this method in the Service layer in the method that is called by the Spring MVC method which returns the Form Backing Object.

I don't think this is a really a convention, it's just an approach I cooked up on my own. I don't really see what any drawbacks are so if somebody disagrees please let me know...

bpapa
Drawback for us is that we're frequently using a given instance as the form backing object for multiple forms. Also, of course, this increases the overhead of adding a new form or adding new fields to a form -- now you have to change the object and the DAO in addition to the form.
JacobM
+2  A: 

Call it overkill if you like, but what we actually ended up doing was to create a generic factory that will take any object and use reflection to (recursively) find all the null properties and instantiate an object of the correct type. I did this using Apache Commons BeanUtils.

This way you can take an object that you may have gotten from various sources (a DAO, deserialization from XML, whatever), pass it through this factory, and use it as a form-backing object without worrying that something you need for binding may be null.

Admittedly, this means instantiating properties that we may not need for a given form, but in our case that doesn't typically apply.

JacobM
@JacobM just for curiosity: To get your goal, do you use BeanUtils.cloneBean method ??? If not, would it be possible you show how to ???
Arthur Ronald F D Garcia
No, I don't use cloneBean. Briefly, the situation might be, for example, that I could have a Contact object that has an Address property which is null. I need to put a new Address object there. So I use PropertyDescriptor.getPropertyType() to get the property's class, and then use Class.getConstructor().newInstance() to instantiate it. The only complexity is that in some cases the property type is an interface; in those cases, for the application I described, I rely on the naming convention that we used for interfaces -- if the interface is IAddress, the implementation is Address.
JacobM
A: 

< form:input path="person.contactInfo.homeAddress.street"/>

Interesting.How I should write if my class like this

public class ContactInfo { String phone; List homeAddress; }

In general, you can bind to something in a collection by using indexes (like with an array). So: Address line 1: <form:input path="contactInfo.homeAddress[0]" /> Address line 2: <form:input path="contactInfo.homeAddress[1]" /> Address line 3: <form:input path="contactInfo.homeAddress[2]" />
JacobM
A: 

public static Person getInstanceForContactInfoForm()

I really wouldnt want to put a method like this on a business object. doing this is binding your "model" to your "view". Person should not, and has no need to know that it will ever be used on a form.

opps, sort of assumed this was a static method on the Person class. If this is on a FormObjectFactory or something like that, it is ok I guess :)