Hibernate never stops surprising me

I have a simple form in my web application where a user can fill in his personal details and address details. User specific fields include firstName, middleName and lastName while Address specific fields include street, city and zip. On the server side, I have POJOs for User and Address. Finally I use Hibernate to map these POJOs to the database. Since, the Address will not be used outside the context of the User, I decided to map it as a Component of the User class.

The User class and its corresponding mapping is given below:

@Entity @Table(name = "user")
public class User {

     @Column(name = "first_name")
     private String firstName;
     
     @Column(name = "middle_name")
     private String middleName;
     
     @Column(name = "last_name")
     private String lastName;
    
     @Embedded
     private Address homeAddress;

     ... Getters and Setters
}

The Address class is mapped to User as a component. You can see the specifics of the mapping below.

@Embeddable
public class Address {
     @Column(name = "address_street")
     private String street;
     
     @Column(name = "address_city")
     private String city;
     
     @Column(name = "address_state")
     private String state;

     ... Getters and Setters
}

As you may already know, mapping components using hibernate is a very useful feature. This feature and support for nested components and components referring to other entities are the primary source of support for rich and fine grained domain model in hibernate. But while i was using Component mapping, I recently stepped on an interesting Feature (or it could be an Issue) and I was happily surprised by it.

Want to know the surprise? Keep reading…

In this case you map an Address as a value type using @Embedded annotation in the “homeAddress” field of the User class. The Address class itself is declared to be @Emeddable. This is the standard Hibernate/JPA way to map value types. The Address class has street, city and zip and it gets stored into the same table as the User class’s table. Now, when you insert an instance of User into the database, while specifying all null values for Address‘s fields maybe because the user didn’t give his address, then what would you expect in return at some point in time when you retrieve this User back from the database.

I for one expected user.getAddress() will return an Address instance. Then address.getStreet() will return null. But that is not what happened. user.getAddress() returned null by itself. That was interesting and even helped me in my case because, if the user hasn’t given any details for his home address, then it probably means that his address itself is not there in the system. So, returning null for getAddress() is semantically the right thing to do. I was surprised and when i checked the hibernate documentation it was even mentioned there that if all properties of a component are null, then the component itself is considered null.

In another situation this could have been bad, I don’t know, but for my purpose I was happily surprised with this nice touch from hibernate. These kind of small things is what differentiates a great product from a good product. Ain’t it?

Ganeshji Marwaha

I spend my days as the Director of Technology for Mobility practice and help my clients design enterprise and consumer mobile strategies. Mobile Payments, Digital Wallet and Tokenization technologies are my areas of specialization

  • Jeff

    Could be, but the fact that it was an unexpected result automatically makes it an undesirable result. There are certain conventions. When a framework breaks them without thoroughly informing the developer, hardens development instead of making it easier and faster.

  • pangea

    I’ve experienced the same thing. πŸ˜‰

  • Ganeshji Marwaha

    @Jeff: In a way you are correct. But, in my case, although i didn’t expect that result, I felt that it was a nice gesture from hibernate. And it was documented as well.

    @Pangea: πŸ™‚

  • Isn’t that reasonable. Thanks for pointing it out though.

  • Stephen

    We hit this problem in the early days of us using Hibernate. It caused us so many problems that we eventually created a custom version of Hibernate which changes the functionality, so that a null component would never be returned – instead (in your example) an empty Address would be returned.

    I have previously requested that Hibernate support this as an option, but it fell on deaf ears. So we have ended up maintaining our own tweaked version of Hibernate as a result.

    My impression is that the Hibernate team – Gavin King in particular – didn’t agree with the change at a fundamental level, even though it appears to have caused similar problems for a number of developers. See
    http://opensource.atlassian.com/projects/hibernate/browse/HB-31
    https://jira.jboss.org/jira/browse/HIBERNATE-50

  • I don’t know how you guys could possibly perceive this behavior as “surprising”, “unexpected” or “undesirable”. Hibernate has featured this behavior since the very earliest versions, with *very* few complaints (just look how few votes those enhancement requests have, over the course of the last 9 years). And the behavior is prominently documented.

    And no-one has yet come up with anything remotely approaching a good usecase for making this configurable. Just look at the weak-ass, contrived examples in those issue reports. An Address where all attributes are null? Seriously? You’re trying to tell me that that somehow represents something different to a null Address? A MonetaryAmount which has neither an amount, nor a currency?? That represents something other than an unknown monetary amount? Give me a break.

    Seriously, the idea that an object with all null fields can possibly represent something meaningful is deeply unlikely.

    So there is no chance that we will ever change this behavior.

    To Ganesh: it’s no surprise, and no coincidence that it turned out nice in your case. We designed it to work like this, because this is always the Right Thing.

    To Jeff: tthere is indeed a very clear convention: all null attributes implies a null object. That’s the convention. The framework isn’t breaking it.

    To Stephen: if this is giving you “many” problems, you’re doing something wrong.

    C’mon folks, explain to me how an Address with all null fields represents something different from an unknown address. The effort of trying to explain this will force you to think the problem through far enough that you will realize why this is just nonsense!

  • Ganeshji Marwaha

    @Gavin: I agree with you that the documentation reflects this feature and this was a nice touch from hibernate and I happily welcomed this feature in my case.

    But that isn’t to say that everybody will like it particularly because this is a value type mapping that ends up being in the same table. A developer has created an instance and saved it to the database, and when he queries back for the same, he gets null value, and you claim this as not surprising. Well, even if you claim that way, It sure was surprising to me and you cannot deny that.

  • OK, but you need to remember that at the database level we can’t distinguish “null address” from “address with all null attributes”, because of the data model *you* have chosen πŸ™‚

    I can turn your argument around, and hypothesize another programmer who saved a User with a null Address to the database. And then he was *really* surprised when he loaded the User from the database and discovered that Hibernate had filled in a stupid totally broken Address object with all null attributes. Now that would be *really* “surprising”, “unexpected” and “undesirable”.

    Hibernate simply can’t know whether you saved a null Address or a non-null Address with all null properties when it looks at the database. It has to pick one option or the other. So it picks the non-crazy option and doesn’t create an stupid broken Address object πŸ™‚

    Now, if you really need to distinguish between null Foo and Foo with null attributes, you need to pick a different data model. (Use a one to one association or something like that.)

  • And yes, it is theoretically possible to add some kind of extra “discriminator” column to the database that specifies whether the whole Address object is null or not.

    But seriously. Future developers are going to come along and look at your database schema and wonder which end of the crack pipe you were smoking when you decided that the ADDRESS_KNOWN column was needed in addition to STREET, CITY, STATE, ZIP πŸ˜‰

  • Ganeshji Marwaha

    @Gavin: You are absolutely correct. Hibernate has no way to know if only the values were null or the entire object was null when it was saved. So, hibernate is choosing the saner among the two alternatives it has. But you are forgetting the third option. Although it is nice of hibernate to select the saner of the 2 options, it could also leave the decision of which is saner to the developer using it.

  • Ganeshji Marwaha

    @Gavin: And you can always default to the current option #2! But yes, if not many developers have voted for that issue, most likely option #1 is not very popular among developers and the hibernate team didn’t find enough motivation to add that in. It is not like you guys don’t have any other feature to implement. πŸ™‚ πŸ˜‰

  • Hibernate already has waaaay too many switches. If I had my time again I would remove features, not add them.

  • Stephen

    Hi Gavin, thanks for taking the time to comment on this.

    I last looked at this stuff several years ago, so I may misremember the details slightly, but here’s basically what our main problem was:

    Take a Customer entity, which contains an Address component. Our entities would always ensure that the Address was initialised, eg

    private Address address = new Address();

    A lot of our code is generic, using reflection to read/write values to the model. So for example, we would have code which would essentially behaves like the following

    get:
    String street = ReflectionUtil.getValue(customer, “address.street”);

    set:
    ReflectionUtil.setValue(customer, “address.street”, street);

    For the ‘get’ case, we could get by with returning null if address was null.
    For the ‘set’ case, this would fall over because customer.getAddress() would return null, and so we could not set the street value.

    There was no obvious way of ensuring that the address would be created automatically where necessary. We tried changing Customer.getAddress() to return a new Address if it had been set to null, however this would then cause Hibernate dirty checking to get confused and decide that the object had been changed and needed to be persisted again.

    We tried several ways of working around this problem, but none worked 100%, and eventually changing Hibernate to work how we needed (and expected) was the solution we ended up with.

    I’d be interested to know what would have been the recommended way of fixing the above problem.

    Gavin I agree that conceptually a null Address is no different to an Address with empty values, I don’t think I’ve seen anyone arguing against you on that, however from a coding perspective there was definitely a difference, and at least in our case the way Hibernate handles things was not what we wanted or expected.

    Point taken that Hibernate has no way of distinguishing between the 2 cases (all empty values or a null component), hence the suggestion/request to have it as a configuration option.

  • Thai Dang Vu

    Hi Stephen,

    Could you tell me the reason you have such a thing like

    ReflectionUtil.getValue(customer, β€œaddress.street”)

    and the reason you don’t write customer.getAddress().getStreet()?

    The thing you are doing is very error-prone, IMHO, because “address.street” is a string (i.e. you can type anything there and even Idea will not show error if you type “adres.stret”) while even Eclipse will give code suggestion/completion for customer.getAddress().getStreet().

  • Ganeshji Marwaha

    @Stephen: You have a clear challenge there assuming that your problem can only be solved using reflection. Hope @Gavin answers your question.

    @Thai Dang Vu: I am sure @Stephen is not using reflection just for the heck of it. I guess, it is more of a platform that he is building that requires runtime binding and is forcing him to use reflection

    @Gavin: Right on. I agree that there are too many features and switches in hibernate that gives a feel that it is complicated to use. But I also feel that although many modern frameworks like Rails, Grails etc prefer to limit features, frameworks like spring and hibernate are established as extremely configurable and customizable. That way, they can be used as general purpose frameworks for a wide range of applications. If you prefer the modern approach to frameworks like your work on Seam, then hibernate wouldn’t be as performant and wouldn’t have achieved mass adoption as it enjoys today. Don’t you think?

  • Stephen

    @Thai / Ganeshji, you’re right, the example looks a bit weird, and the actual code is indeed running inside a generic framework we’ve built, which does the dynamic binding at runtime using reflection. Sorry for not making that more clear initially, tho I think my post was already too long anyway πŸ˜‰

    Note however, that even if we ditched reflection, we still couldn’t just write
    customer.getAddress().getStreet()
    as we’d still have to specifically code for the case where customer.getAddress() returns null.

    One of the rules we use when building our entities is that we don’t allow the components (eg Address) to ever be null, as we found that avoids issues such as the above. Our problem was that Hibernate’s default behaviour didn’t seem to allow us to enforce that, and so we ended up creating a custom version which did.

  • Pingback: uberVU - social comments()

  • Stephen Colebourne

    @Gavin,
    I understand why you see null as the correct result, it fits well with the database perspective (you don’t know what the state is). However, I have in a past life setup the data model such that linked beans like this are never null – it avoids NPEs. I would prefer Hibernate to be able to respect that (maybe inspecting an @NonNull annotation?)

    Your analogy to money (null amount/currency) is a false analogy. Money is a value object and has absolutely no meaning when incomplete (also dates/times). Address is a domain object, and does have meaning with some, or possibly all, null fields (eg. data not yet collected from the page). As much as anything, it depends on your perspective of the data model.

  • HFS

    Seriously, null checking is abominable, you should always return empty lists and empty objects (with null fields).

    If you wanted to list all the customers and their addresses, you’d have to do a null check before calling something like toString(). It is just stupid.

    =/

  • Kent

    Nobody is forced to use reflection. It is a design choice they make and it comes with trade-offs, like any other design decision. If there were a perfect design, we’d all be using it, end of story. I appreciate hibernate’s current behavior. It is indeed the most sane of all the options. If you need to avoid null pointer problems, go ahead and instantiate the Address object, initialize all the fields to default values (like empty strings, for example). Then, you can add a method to your entity class that tests for “null” by testing for all empty (or default) values.

    To me, a small design decision like this, although it requires a small amount of effort and training for members of our team, is waaaay better than forking hibernate and maintaining it ad infinitum.

  • Stephen

    @Kent, it’s not about having a “perfect” design. It’s about making a design decision about how we wanted our model to behave, then finding out that Hibernate didn’t support it (and seemingly refused out of principle to support it).

    We tried numerous workarounds, none of which actually worked. I didn’t consider tweaking Hibernate until we’d tried several other options, as I expected it would be difficult to find the appropriate code and adjust it safely. As it turns out, the Hibernate code was well written and easy to follow, and the change was trivial. We’ve used this patched version on numerous large projects since then, and I have no doubt that we made the correct decision.

    I haven’t seen any give any real-world examples for why setting the Address to null is better, only claims of it being more “correct” or “sane” – are there any practical coding examples where it helps the developer? Gavin claims the examples in the issue tracker are “contrived” and “weak-assed”. So where are the examples of where it’s demonstrably better to set to null?

    I don’t believe your suggested workaround – initialising to empty strings – would work on Oracle at least, as Oracle converts empty strings to null, so you would end up with a null Address object once more. Even if it did work with strings, what about other data types, eg dates? Since it doesn’t appear to generalise to all situations, this would not be an acceptable option for us.

  • Stephen, then what is broken is your braindead ReflectionUtil.setValue() stuff, which is unable to properly construct object graphs. Don’t try to blame Hibernate because *your* generic framework is fragile. You agree that Hibernate does the Right Thing conceptually, so it’s clear that your generic code is the bit that is conceptually broken.

  • “Address is a domain object, and does have meaning with some, or possibly all, null fields (eg. data not yet collected from the page).”

    What complete nonsense! An address with all null fields means you don’t know the address. End of story. (Ask your users if you don’t believe me.) You are getting confused between an object which represents the business domain, and objects you use to collect data in a user interface. The objects managed by Hibernate model business concepts. They are absolutely *not* helper classes for building user interfaces.

  • “Seriously, null checking is abominable, you should always return empty lists and empty objects (with null fields).”

    Empty collections definitely. “Empty” objects no way. I hope I never, ever, have the opportunity to see code written like this. What a mess!

  • just curious

    why do the author delete Gavin King’s comment?

  • Ganeshji Marwaha

    Due to some odd reason Gavin’s comments were marked as spam, maybe because he posted a few posts within a short gap. The issue is now rectified and Gavin’s comments are back on.

  • Stephen Colebourne

    > The objects managed by Hibernate model business concepts. They are absolutely *not* helper classes for building user interfaces.

    @Gavin, Your answer is about imposing one design approach on the user, the one you/Hibernate believe is right. Other developers, including me, believe there are alternatives – are you willing to accept that there are other viewpoints than your own?

    Put another way, I’d like to see Hibernate be a servant of its users not the master, ie. it should be a library, not a framework.

  • Folks,

    Seems like everyone here except Gavin is thinking about this like it’s an object problem.

    It’s not.

    Hibernate exists to map a relational model into an object one. There are consequences to this. There always have been. The null reference to Address perfectly models the relational behavior in the database.

    If you don’t like that, your framework needs to do the necessary machinations to “perfectify” your objects for consumption…Hibernate did the right thing it was asked to do. Map the relational data (no address FK column) into the object model (a null Address reference).

  • Stf

    I really agree with gavin but to be honest hibernate can return not null component.

    If you really want a not null component…
    just put a custom usertype that returns empty string instead of null for the zip. As one of the field isn’t null… you will have your adress not null.

    for null checking… replace all user.getAddress()!=null by user.getAddress().isValid()
    But with this strategy, i’m not sure you won something I prefer a “fail fast” approach.

    And a tool like findbugs can prevent you from undesired NullPointerException πŸ˜‰

  • Stephen

    @Gavin – I don’t believe I said that Hibernate does the “Right Thing” – just that conceptually (and from the database’s point of view) a null Address and an Address with empty values are equivalent.

    It is my experience that setting to null causes more problems than setting to an Address object with empty values does (see examples above). Could we work around all of the problems? Sure. Would we get any benefit? I don’t see any. It appears we’d just end up with a load of unnecessary null handling in both the framework and application code.

    Bottom line is I believe that there are 2 ways of handling this case conceptually, but that in practice hydrating to an Address object with null values leads to cleaner code (and less chance of NPEs) elsewhere.

    Again – can anyone give me any examples where setting the Address to null is actually beneficial, and not just the “Right Thing”?

  • Alexandre Jacques

    I have to agree with Gavin. It makes no sense at all having an empty address object in whatever situation. I mean, what’s the use of an Address business object (actually a physical location somewhere) with no data in it?!

    I was never surprised by this behavior. I’ve been using @Embedded for a long time and I would be very disappointed with Gavin if it returned anything other than null. πŸ˜‰

    Just my 2 cents.

    Regards

  • Robert St. John

    Developers that don’t do null checking are lazy.

    @Stephen – I believe that the fact that setting the Address to null is the “Right Thing”, as you say, makes it intrinsically beneficial. I expect, above all, consistent, correct behavior from any framework.

  • Stephen McLeod (aka Stephen)

    @Robert – I presume you are aware of the NullObject pattern, and thus believe that it is an anti-pattern, as it’s main purpose is to avoid unnecessary null checking?

    I would argue that having object references which you know are never null is a lot better than having developers throwing in null checking in the code ‘just in case’.

    My models, application and framework code are 100% consistent, in that the Customer.address will never be null, and all code can happily assume that is always the case.

    I’ve still seen nothing to convince me that a null value is any more correct (“Right Thing” was Gavin’s words, not mine) than an Address with null values, or any advantage that this would bring.

    Correctness in this case seems to be in the eye of the beholder. Nobody has given any practical arguments why a null value is more correct – just stating it as fact does not make it so, nor does claiming that it is the expected behaviour (despite it having apparently taken a number of people by surprise).

    I was ready to be converted, or at least enlightened, but leave disappointed.

  • Robert St. John

    I am aware of the Null Object pattern, but I stand by my statement. The existence of a pattern that exhibits the behavior you desire does not make that behavior correct with respect to any specific problem. In this specific case, you know that the objects in question can be null, and you know under what circumstances they will be null, therefore you should check for null. Null checking, in this case, is not a “just in case”, unnecessary measure, it is handling an expected application state.

    I think the practical argument for the null value is what Gavin said in post #8. The object tree most accurately reflects the database state, given the use of @Embedded values. Had you used a one-to-one mapping, and there existed a related Address row with a foreign key value and nothing else, then the empty, non-null object that you desire would most accurately reflect the database state.

    Like any problem in software development (or any other discipline), there are multiple solutions and as you say, correctness is in the eye of the beholder. Gavin implemented the behavior that he perceives as correct, and defined it well. You changed that behavior to what is ideal for your specific application, and that behavior is well defined in your shop.

    All frameworks, including the Java SDK itself, have behaviors that can be expected by one developer and unexpected by another, but all developers must learn these behaviors and code accordingly in the context of a specific problem.

  • Hibernate already has waaaay too many switches. If I had my time again I would remove features, not add them.

  • charly

    I have one fix: if your framework is unwilling to listen to your needs, stop using it. Try iBatis.

  • daggerrz

    Hoping to resurrect this interesting thread. We’re having issues similar to Stephen, i.e. binding Wicket input fields to expressions like “customer.address.postalCode”. I agree with Gavin’s points on null semantics and believe that if we _really_ want to always ensure that getAddress returns an address, this should be done in the setter.

    One point that Stephen mentioned, and I think got lost, is the fact that Hibernate’s dirty checking flags a soon-to-be-null address component field as dirty. In other words, if the customer instance is loaded with null address, the address accessor (yeah, I guess it has side-effects) initializes a new address instance when rendering the customer’s address (OpenSessionInView) and the customer will be flushed back to the database. The address fields to not change, but auditing status will.

    So the question is, wouldn’t it be reasonable for Hibernate to ensure that the address component really has a persistable state change in order to flag it as dirty? IMO, this would not break the null semantics (rather strengthen it) and at the same time solve our and Stephen’s problems. It might have a slight performance impact, but probably only for systems that would rely on this feature.

  • Ed

    What about if a component contains an empty collection?

    Collections don’t follow the hibernate null semantics, so all the fields in my component are never all null, so it will always exists :(… And I want it to be null also if it contains an empty collection.

    Suppose that the Address contains a some collection of logging about he delivered mail at that address.
    I think the component address should be null also if this collection is null, not ?…
    I also posted a question about this in the forum:
    https://forum.hibernate.org/viewtopic.php?f=1&t=1006066

  • ghd

    Thanks ! wansantg2zxy.

  • Bill Smythe

    This references Mr. King’s terminology when responding to users of the application he is partially responsible for.

    Terms such as ‘stupid’, ‘meaningless’, ‘nonsense’, etc are quite unprofessional. This is not a good way to represent what is a very good argument by those in favor of empty obj elements over a null (no obj?).

    If it causes users issues and wasted time, then add a switch that allow them to CHOOSE what is returned – the theoretical tirade is not only unprofessional, but immature.

    If Stephen had an issue with this concept and wasted hours trying to figure out why, then there are hundreds if not thousands of other devs who wasted that time also.

    This is not a theoretical issue as much as it is a feature desired by users – regardless of how many persons voted for a particular improvement on a site that I hadn’t heard of until now – I use apps that behave in ways I do not expect, and it usually results in wasted time trying to figure out the ‘logic’ that differs from mine – right or wrong.

    Gavin, get over it – It is more important that ‘your’ app behaves as expected so developers are not wasting time just to get to an ‘aha’ moment. Yes, you are probably very brilliant, but that doesn’t make me any money if I do not get expected results from your product.

    Thanks Ganesh for hosting this site! Degrading terms aside, nice theoretical discussion!

    Bill

  • Kalyan Dasika

    We started our model with a similar approach few years back.. (Address as a component) and then realized we started adding entities like Clinic (has Address) and then we also had to support User to have multiple addresses (moved to new location and as per regulations you keep a list of old address on profile) .. so the Address evolved from a component to an Entity. So a normalized data model would return an Address object ( and not null even if it is undesired) though all the fields are null. If it is a valid condition to be in or not depends on how you handle the use case.

  • Ganeshji Marwaha

    @Kalyan #44 – Sure Kalyan, what you say is right. Depending on the use-case and the size of the application, an Address could either be a component or an entity. When it is an Entity, this doesn’t apply. Still, it is something good to know about. Learning never stops right. πŸ™‚

  • Jakob Oswald

    Hello there,

    actually I am facing the component null problem at this very moment and would be happy about a switch, too. I will explain why in my opinion (or at least for my current data model) it would be a good idea.

    I have an Address component, which consists of an IAddress interface and an abstract class AbstractAddress. The interface specifies a validate method which validates the consistency on application level for concrete Address-implementations and a Mapper that maps the IAddress objects to value objects and vice versa. The mapper actually doesn’t know which concrete class to instantiate if it hits a null Address (e.g. in an update of the entity), but the domain object owning the address does. This will probably leave me to add a createAddress method to the owner, which results in extra work to do.

    I hope this makes sense. Any better solutions are welcome.

  • In another situation this could have been bad, I don’t know, but for my purpose I was happily surprised with this nice touch from hibernate. These kind of small things is what differentiates a great product from a good product. Ain’t it?

  • Hello to the one who created this post! I am a certified blog-addict and I just love acknowledging bloggers for their great jobs to let them know that somebody appreciates their works so that they’ll continue making such brilliant posts. Congratulations for this one-of-a-kind post and thank you because your work was added to my bookmarks!

  • Saat sedang browsing

  • iseng-iseng saya pun

  • vBagi anda yang mau

  • vAnda dapat mengetikkan

  • that’s nice