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?
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.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With