I looked at the comments here and I've had the exact same problem as the person asking this question:
I read all 3 articles
� Why I like EJB 3.0 and really like EJB 3.1, ... � Heavy EJBs, lightweight POJOs, .... � What happens, if you start with EJB3.x ...
and didn't see where you compare a part of EJB3 with Spring (I say 'a part of EJB3' because I heard that EJB3 covers something like JCA that Spring doesn't).
I came to EJB3 from Spring and there are a couple of things that are bugging me (I'm not good at EJB3 and not good at Spring either, so I'm very thankful if any of you can give me solutions for the following problems I'm facing): - In web-based applications: Spring has OpenEntityManagerInViewFilter. What is the counterpart in EJB3? If you never use Spring and don't know what OpenEntityManagerInViewFilter is, let me explain it in my own knowledge: for example, to display the information of all the students of a teacher in JSF, I write something like
The OpenEntityManagerInViewFilter open an entity manager when this JSF page is rendered and doesn't close it until this JSF page finishes being rendered. So we won't have the lazy initialization exceptions.
In EJB3, I have to eager loading all the students associated with a teacher in the JQL query or write the JQL like
select t from teacher t left join fetch t.students
or execute 'select t from teacher t' and t.getStudents().size().
All 3 ways in EJB3 aren't flexible because sometimes I need the information of the teacher and his students but some other times I need the info of the teacher only.
- In Spring, when I need to use caches, I have an aroundInvoke AOP class wrapping around a method that I want to provide caching with. A cache implementation (e.g. Ehcache), which is an instance of a class, can be injected into that AOP class. How can I inject an instance of a regular class into an EJB3 session bean? Which annotation should I use for that injection (@Resource?)? How can I create just 1 instance of that class and use that instance everywhere in the application? I'm thinking of creating that instance when the application starts, put it in the JNDI context and use JNDI lookup to retrieve it whenever I need it. Is that a good way to do it or is there any better way?
If you read from the beginning to this sentence, then thank you very much for your time of reading my comment
But the answer, about using extended persistence contect and a @Stateful session bean. I don't get it.
1. I actually didn't compared EJB 3 with Spring, I just described EJB 3 :-) from my point of view. What you are searching for is "extended" PersistenceContext in a @Stateful session bean. Then all Entities remain attached and are lazy loadable.
2. You can use Interceptors (seach for @Interceptor) - very similar concept to AOP for decorating EJBs.
3. There are no Singletons in EJB 3.0 right now. They will be available in EJB 3.1 - but for other purposes (startup, configuration, global cache).
If you only would like to keeep your entities attached and usable outside the EM without eager loading, then all you need are stateful session beans with "EXTENDED" EntityManager.
thanks for your comment,
Could someone explain this in more detail? Why do I want to use a @Stateful session bean? I only want to display this information and close the persistence context, so why a @Stateful?
I'm sure I'm missing something here. My problem is the same as the one asking the question. I don't want to get lazy loading exceptions and calling all getters or doing a manual fetch join is cumbersome to say the least. And if I have lazy instance variables in the same object, like String's etc, then I don't think fetch join is even an option?
PS. I copy pasted from that blog as the entry was written in June and who knows if he/someone will answer if I write it there. I clearly stated the source and commented out any names, so I would assume it's all right. [ November 15, 2008: Message edited by: P Kuling ]
Unfortunately, the issues you mention are not that easy to explain within the limited scope of a forum post or two. The short answer is that JBoss Seam in Java EE 5 and WebBeans in Java EE 6 solve these problems (and many others) quite elegantly. I would recommend that you take a look at Seam in Action. Dan Allen does an excellent job explaining all of the issues that you mentioned (I know he is also active on the Manning Author Online forum for Seam in Action: http://www.manning-sandbox.com/forum.jspa?forumID=354).
As a complete aside, having developed several EJB 3 and numerous Spring/Hibernate systems, I can honestly tell you that the lazy init exception you mention is a little overblown/oversold. I haven't encountered it *even once* in a real-life application. As another side note, EJB 3 vs. Spring is actually more or less a false dichotomy that *most developers gain little from*. I've personally designed systems that integrate EJB 3 with Spring quite naturally. I've recently presented on this very topic: http://www.ctjava.org/camp2008/sessionB.jsf?cid=1351.
P.S.: I'm glad you found Adam's blog. Feel free to contact him directly, he will likely respond. Being a gruff German, he is often not bound by some of the implicit rules of political correctness some of us feel we have to be encumbered by :-). [ November 15, 2008: Message edited by: Reza Rahman ]
Independent Consultant — Author, EJB 3 in Action — Expert Group Member, Java EE 6 and EJB 3.1
Joined: Aug 07, 2008
Thank you again for your answer!
From a brief look, it seems like Seam is forcing us to use JSF (please correct me if I'm wrong), which unfortunately takes it away as an option for us. Also as it's not a standard, it competes with Spring and if I'm not wrong Spring is more popular. I am looking into Wicket for our presentation layer, and it looks very nice, but that's off topic for this discussion. :-)
I have had problems with lazy loading exceptions when using JPA and Hibernate as persistence provider, and I know it's a problem a lot of people seems concerned with. It might be due to some kind of architecture issue which I've overlooked, as it has never been a problem for you.
I define a problem as a cumbersome step which makes development slower or even results in a solution with performance problems. It's not a problem to find these lazy loading exceptions when they're introduced, as it shows itself in the most basic (and automated) testing. However I've found no good, clean solution, and that's a problem, maybe I've missed something and there are nice solutions. And I would be thrilled to here how these kind of issues are solved.
I'll make my case:
The general recommendation seems to be, make as much as possible lazy, though fields you use almost every time you use an entity should be eager. If you have an architecture as the one I described above, entities will be passed from persistence to business and from business to presentation and used along the way. That's not a problem for persistence & business as they are both inside a persistence context. However when you get an entity from an SLSB into the presentation layer, the persistence context will be closed. This in turn means that if you try to access a lazy field you will get a lazy loading exception. The only solutions to this problem that I know of without introducing a new framework are:
Make sure to call all getters in each entity before they are passed from the business to presentation layer.
Introduce a new object for data transfers, essentially a data structure, a real POJO (not a proxied JPA entity). The business methods which the presentation layer uses then returns this object which gets its data copied from the JPA entity.
Perform a fetch join using JPQL for retrieving the entity in the business layer and returning it to the presentation layer. All external dependencies will get loaded.
Use eager for everything.
Have a special method for each manager in the business layer of the form foo getEagerVersionOfFoo(Foo foo). You will pass it a Foo instance foo which has lazily loaded fields, inside the method in the business layer it will call all getters (or maybe perform a fetch join) and return the loaded entity back to the presentation layer. The presentation layer is able to use any getters now and you won't have to create special versions of the methods in the business layer to indicate that you need an eagerly loaded result.
But all of these methods have their issues:
You have to synchronize the getter calling in the business method with the fields which are lazy in the entity manually. Even if you don't miss anything it's cumbersome. To have a way of indicating that the returned entity is going to the presentation layer you'll have to introduce new methods, or modify the interface of existing ones.
This method has the same issues as the previous way and the added problem that you will have to synchronize two classes manually as well. You can't get a lazy loading exception using this method, instead you'll get a null pointer exception, or a default initiated primitive.
This method takes away the ORM features almost completely, and forces you to write your own JPQL queries for almost every kind of information retrieval. And what about if I have a String which is set to load lazily? Will that work? (I think the fetch join only cares to load external dependencies eagerly. But I'm not sure and I'll have to investigate that aspect further.)
This isn't possible if you are using Hibernate as your persistence provider, as it can't load multiple bags eagerly. In other words, you can't have two List<String> that's loaded eagerly in the same entity (which the JPA specification seems to allow). Then you're back in a situation were you have to handle the lazily loaded entity in some kind of way. It's also questionable if having everything as eager is good for performance reasons.
It's still cumbersome to synchronize the getters with the fields which are lazily loaded in the entity. And there is still one method introduced in the business layer just because we're using JPA.
Of the above solutions I prefer the last one, as it minimizes the business class interface changes which are needed for this specific 3-tier architecture. However it still isn't perfect. All solutions seem to break the layer separation and both the business and presentation layers are affected by the choice to use JPA for persistence. But maybe this can't be avoided using any ORM framework.
I'll look into if Spring has a nice solution for this. And I'll also look into the solution suggested in the blog comment above, if I can find any more information. I'll mail Adam and see if he has time to and feels like answering over mail, here or on his blog. [ November 17, 2008: Message edited by: P Kuling ]
Joined: Feb 01, 2005
Sorry for the delay in responding. Not really sure what else to add beyond what I already said, but I'll add the following comments in case it helps:
* If I remember correctly, JBoss was extending Seam support beyond JSF, but I've never used it. It might be worth checking out.
* Spring definitely has more of an install base than Seam, but Seam adoption appears to be accelerating, at least in the short term. Personally, I like the Seam/Google Guice/WebBeans DI features better, all other things being equal.
* A lot of Seam is being standardized in WebBeans 1.0, as is a lot of Google Guice. Conversely, it appears that SpringSource will support WebBeans.
* I doubt you have a fundamental architectural problem. When I hear about the Hibernate lazy loading issue, it's often from folks at the early stages of learning ORM "tinkering with" or "testing" ORM mapping they just wrote. The problem there is, this kind of code often does not reflect realistic use-cases. I'll explain a little more:
- I actually never override JPA loading strategies by hand. With very rare exception, I find the defaults to be the most appropriate and performance friendly settings (lazy loading results in additional database round trips -- something to avoid doing frivolously). By default, JPA loads all basic field values, one-to-one associations and many-to-one associations eagerly. Conversely, one-to-many and many-to-many association are loaded lazily.
- To some degree this depends on how your UI is designed, but for a vast majority of cases, the defaults work because a given screen only uses the data from one primary domain object or "very closely related" domain objects. In the rare cases where this is not true, I have alternate "load" methods that take a "loading strategy" argument indicating resolving all associations (in theory, the loading strategies could include other more "intermediate" states). I generally do this via JPQL fetch joins, but lazy loading would work too. I prefer JPQL for performance as well as the fact that I am very comfortable with SQL-like code. I really don't see ORM as a query language replacement; I see it more as a way of getting rid of a lot of boilerplate code (this is also the view of most persistence experts I talk to). In fact, the feedback many developers give me is that they almost prefer JPQL to some of the other functions in the entity manager API.
* I have tried *multiple times* to convince the Hibernate team to simply leave the entity state as-is in situations that cause the lazy loading exception instead of causing a nasty run-time error. Every time I bring this up I get an overly-pedantic/argumentative/alpha-geek-like viewpoint more or less designed to stalemate the discussion, so I have given up. *As a very interesting data point, neither TopLink/EclipseLink neither Kodo/OpenJPA throw the equivalent of a Hibernate lazy loading exception.* *Indeed, both lazily load data even when the entity manager instance is out of scope.* There was some talk in the JPA 2 spec to better standardize this behavior properly, don't know if this went anywhere...especially given the aforementioned "alpha geeks" that seem to know something the rest of us don't :-(.
Thank you for helping me and writing these informative answers! I think I have a good grasp of how you handle this problem now. I have some last questions below and then I think I'm finished. :-)
In the rare cases where this is not true, I have alternate "load" methods that take a "loading strategy" argument indicating resolving all associations (in theory, the loading strategies could include other more "intermediate" states). I generally do this via JPQL fetch joins, but lazy loading would work too. I prefer JPQL for performance as well as the fact that I am very comfortable with SQL-like code. I really don't see ORM as a query language replacement; I see it more as a way of getting rid of a lot of boilerplate code (this is also the view of most persistence experts I talk to). In fact, the feedback many developers give me is that they almost prefer JPQL to some of the other functions in the entity manager API.
It seems like you're using method E (which I described above) with Fetch Join.
The specification doesn't mention if FETCH JOIN initializes lazily loaded fields ("22.214.171.124, Fetch Joins" in "JSR 220, Persistence") for basic types. If it doesn't, it works only because you're using the defaults and don't have any of the basic types as lazy in your JPA entity.
You have a special method in your manager classes for initializing lazy enteties. It breaks separation of concerns as the manager class shouldn't have to deal with persistence. But there is probably no way around it.
Of course ORM can't replace a query language completely while still having acceptable performance, not today anyway. My objection was that this means you'll have to write a Fetch Join query for each and every JPA entity which contains lazily loaded data that you want to access from the presentation layer. And you will have to synchronize your JPQL query manually if you change the entity and add/remove lazily loaded fields. To me that feels cumbersome and like having to produce boilerplate code.
I would have liked a method in EntityManager for loading everything which is set as lazy. It would have been nice to have and it would also have been dynamic, not forcing us to keep two parts of the code synchronized manually.
And as a last comment:
Using the above approach. If I have a User object containing lots of information about the user like address, a long String containing* a presentation etc. Then it's not nice if I have to retrieve all that information if I'm only looking for the credentials information. And that can't be good for performance. I'd rather take the roundtrip to the database when I in 0.001% of the case actually am looking for that information. I think there are lots of cases when lazy loading is motivated. But that's just my personal opinion, and I'm not an ORM expert or even very experienced with any of the technologies. :-)
* I'm using containing loosely here. You may interpret it as local fields in the entity or external objects with a one-to-one relationship with the entity.
*Indeed, both lazily load data even when the entity manager instance is out of scope.* There was some talk in the JPA 2 spec to better standardize this behavior properly, don't know if this went anywhere...especially given the aforementioned "alpha geeks" that seem to know something the rest of us don't :-(.
It would have been great if they would have standardized that behavior as part of JPA 2.
For JPA 1 I've seen nothing that indicates that you may not have more than one Many-To-Many or One-To-Many in one and the same entity which have eager loading. To me that indicates it's allowed to have for example more than one List<SomeObject> in an entity loaded eagerly.
Yet if you try to do this using Hibernate it throws an exception. They explain it as a limitation in SQL and that it's conceptually not possible. Still the lazy proprty on a field is a hint, and if they can't conform to a configuration as it's impossible they should just ignore the hint. But they take the hint to seriously and instead throws an exception. This is an example of something they won't change: http://opensource.atlassian.com/projects/hibernate/browse/HHH-2980
Steve Ebersole sarcastically comments on that bug report that 'With all these "un-spec compliant" complaints bandied about its amazing we passed the JPA TCK.' and I have to agree. Yes, that is amazing and just plain wrong. :-/
It doesn't seem like the Hibernate team want to follow the standard. If they haven't already, I think they should be invited to take part of the JPA 2 specification. If they feel that there are strange decisions taken during the standardization process maybe they would feel better if they could participate. Hibernate is huge when it comes to acting as a JPA persistence provider so it seems logical. If they don't follow the standard it affects the whole JPA standard in a very negative way. Well, enough rambling from me about that. [ November 18, 2008: Message edited by: P Kuling ]
Joined: Feb 01, 2005
Having a bit of trouble deciphering what more I can tell you :-). Feel free to be very specific about questions, even in form of separate bullet-points or posts...
Here are a few more comments as I could interpret:
* Lazy loading for basic fields are optional in JPA 1.0. Indeed, most persistence providers don't implement it. Again, in truth, it is rarely used. * One other thing to keep in mind is the usage of distributed caches for read-only or read-mostly data. The user entity in your example is probably a good candidate for that. With distributed caching in place, lazy vs. eager loading becomes less of an issue. In fact, it's almost better to eager load most entity data. * I get your point about separation of concerns. As you said, there isn't a while lot of ways around it right now and it is a relatively minor case. This is a bit tongue-in-cheek, but one way to get around this, of course, is to use something like TopLink essentials that has less lazy loading quirks :-). * Red Hat is part of the JPA 2.0 (JSR 317) EG. I do agree that JBoss seems a little ambivalent about Java EE at times. Then again, almost everyone in the EG pushes their own agenda from time-to-time, has a "not invented here" attitude and is remiss in admitting their own problems. It is just that some people seem to feel more entitled to do that than others :-). I'm not just talking about the Red Hat folks. Some other people that are often "better regarded" do the very same things...
Joined: Aug 07, 2008
Well that was a good wrap-up. Thank you so much for your time! I'll be sure to look into your book, I'm a fan of the "In Action"-series and I'm currently reading Wicket In Action.
Joined: Feb 01, 2005
No problem at all, I see it as a privilege. I hope you enjoy EJB 3 in Action. Feel free to give me any feedback, it's very useful since we are planning a second edition right now.