When all of the values in an @Embedded object are NULL, Hibernate sets the field in the parent object to null. This can lead to NullPointerExceptions if not handled correctly.
There are two ways to handle this:
Make sure code that calls the @Embedded getter handles null return values.
Add a non-nullable field to the embedded object, thus avoiding the behavior entirely.
I suggest to make this optional. I.e. add an annotation which would make Hibernate create an object with it's properties set to null.
In my oppinion, this would improve usability and user friendliness.
Having an embedded object with all props potentially set to null is perfectly valid use case - e.g. an object with optional traits grouped in @Embeddable class; When this is created, the traits are initially empty.
This was reported years ago as a bug, but at that time, it was closed as Won't fix for unknown reason.
JBoss EAP 6.0.1.ER1
Unfortunately I am not able to persuade Hibernate to use field access for my embedded object (moving @Embedded to field or adding @AccessType doesn't help). But using common sense it can not work with that.
Also I have a small modification to the workaround - we will use a bit more semantically correct alternative (instead of ignoring null value, we will interpret it as an "empty object"):
Not sure what have changed since I first tested the workaround, but we have tried to actually implement it in our application and Hibernate again handles everything as "dirty". Loaded state is always "null", new state is always empty entity. So there must be something else to make this workaround work. It does not work as is.
UPDATE: The reason for the non-working workaround is ComponentType#hydrate, which returns null if all its properties are null. Thus it is not possible to have non-null loaded entity state.
I am getting the same with Pavel, debugged all the way to ComponentType#hydrate.
You would need to add handling to the actual reading of a composite out of the ResultSet to handle all tuples as null to mean "create an empty composite instance". That's how "loaded state" is populated. This would require changing org.hibernate.type.ComponentType#resolve from:
to something like:
You'd also need to make certain that this is accounted for in the various equality checking methods (isSame, isEqual, compare, isModified, etc).
Also this will require lots of testing as this is a long standing assumption in Hibernate code.
Ultimately this is very low on my todo list. But if someone wants to work on it and work up a Pull Request, that obviously raises the likelihood that it gets resolved sooner. I laid out the main changes above. Just make sure that createEmptyCompositesEnabled():
delegates to SessionFactory/Settings
is fueled by a user-controlled setting
is disabled by default (opt-in behavior)
This is probably going to be frowned upon by purists, but until there is a way to configure hibernate to ensure @Embedded fields are non-null, I've written an AspectJ to populate the value if null.
This isn't fully tested, and definitely not tested against Collections of embedded objects, so buyer-beware.