Option for injecting empty (non-null) embedded when all columns are NULL

Description

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.

Attachments

1

Activity

Show:

EricB July 8, 2014 at 6:14 PM
Edited

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.

Steve Ebersole October 21, 2013 at 2:42 PM

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:

ComponentType.java

to something like:

ComponentType.java

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)

Markos Fragkakis October 21, 2013 at 10:06 AM

I am getting the same with Pavel, debugged all the way to ComponentType#hydrate.

Pavel Horal August 7, 2013 at 9:21 AM
Edited

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.

Pavel Horal July 19, 2013 at 12:25 PM
Edited

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"):

Fixed

Details

Assignee

Reporter

Labels

Components

Fix versions

Priority

Created September 17, 2012 at 11:38 PM
Updated July 28, 2017 at 7:14 PM
Resolved January 24, 2016 at 11:41 PM