tags:

views:

31

answers:

2

I was reading an article in which the author had implemented an Entity class like this:

@Entity
public class Product {

 @OneToMany
 private List<Part> parts; // note the missing "= new ArrayList<Part>();"

 public Product() {
 }

 // getters and setters

}

I always used to instantiate collection fields, in this case parts, either inline (private List<Part> parts = new ArrayList<Part>();) or inside the constructor because as far as I can remember not doing so would lead to all kinds of NPEs.

I thought that things have changed in JPA 2 and now the JPA runtime automatically instantiates the field using runtime bytecode enhancement or reflection, so I gave it another try, however I still can't get it to work without instantiating the parts field, otherwise aProduct.getParts().add(aPart) would throw an NPE.

So my question is that is it possible to make this work without instantiating the parts field in both of Java SE and Java EE environments using Hibernate as the provider? If so, how?

+2  A: 

My understanding is that the JPA provider can only instantiate the field properly within an entity loaded from the DB. However, if you create a new (as yet transient) entity, you must ensure yourself that all fields are valid. Note that Hibernate/JPA is not aware of a newly created transient entity, until you actually attach it to a persistence context. And if you think about it, it is logical (at least to me): if you relied on JPA/Hibernate to instantiate your objects properly, you would build up a strong and intrusive implementation dependency to it, which would make it very difficult to impossible to ever work without it again.

So leaving the collection property uninitialized may be fine for entities which are never created afresh, only loaded from the DB. For classes where you do create new instances too, the simplest way to resolve this would be to provide two constructors: a default for Hibernate/JPA, and a parametrized one for the creation "by hand". In case you don't have parameters to set, you could also create a static factory method to initialize all required fields with default values.

Péter Török
+1  A: 

If you load an Entity from the datastore then you do NOT need to "instantiate" the field since it will be loaded from the datastore (if it existed at persistence). If the collection was null at persist() then when retrieving it, it will likely also be null (since that is the point of making a persistence mechanism transparent)

DataNucleus
I doubt it, since it would be inconsistent with the usual Hibernate way of returning empty collections for values not found, e.g. in all queries (which is a good practice, as described in Effective Java 2nd Ed. Item 43). But I have no concrete evidence, other than: what could/would be the difference between the DB representation of a `null` collection property vs an empty collection property?
Péter Török
Ok, my response is from a JPA perspective, not Hibernate. Some JPA implementations do recognise the difference between empty and null when persisting and when reading back.
DataNucleus
Interesting, I learned something new :-) Would be nice to know how they represent the difference in the DB.
Péter Török