Adam Bien's Weblog
Loading Lazy (JPA) Relations - With (J)Xpath
Lazy loaded relations often cannot be transferred and serialized to the client. Even in case the serialization were successful, they cannot be accessed from the client for sure. They have to be loaded before leaving the remote-boundary. Either the server has to know in advance which references are interesting to the client, or the client has to communicate it somehow.
The latter case can be easy handled with a nice commons library with the name JXPath. The idea: a XPath expression can be applied to JavaBeans, what eventually causes the invocation of "getters" and so forces the loading of lazy relations. So a simple string can be passed from the client to the server. So to invoke the method Master#getDetail():
public class Master {
private Detail detail;
private List<Detail> details;
public Master(Detail detail) {
this.detail = detail;
this.details = new ArrayList<Detail>();
this.details.add(detail);
}
public Detail getDetail() {
System.out.println("getDetail");
return detail;
}
public void setDetail(Detail detail) {
this.detail = detail;
}
public List<Detail> getDetails() {
return details;
}
public void setDetails(List<Detail> details) {
this.details = details;
}
}
...requires the following code:
public class JXPathTest {
private Master master;
@Before
public void init(){
this.master = new Master(new Detail());
}
@Test
public void lazyLoadOneToOne(){
Object value = JXPathContext.newContext(master).getValue("/detail");
assertNotNull(value);
}
//..
This sample is an interesting extension of the Service Facade pattern. Gateway solves the lazy-loading problem entirely, but requires the introduction of conversational state.
The sample project "JXPath" was pushed into:http://kenai.com/projects/javaee-patterns/
[See "The Problem with Lazy Loading and Transparent Persistence" pattern, page 51, "Essential Complexity Of Domain Driven Designs" , page 266, as well as the Gateway and Service Facade Patterns in "Real World Java EE Patterns Rethinking Best Practices" book for more in-depth discussion]
Posted at 09:00AM Oct 22, 2009 by Adam Bien in Real World Java EE Patterns - Rethinking Best Practices | Kommentare[9]
[my tweets]
Rss My book: Real World Java EE - Rethinking Best Practices


Have you tried JBoss Seam? With Seam, all the Lazy Loading problems are gone. Of course, that alone doesn't justify using a complex framework like Seam, but this is one of it's many cool features.
Claus
Gesendet von Claus Hausberger am October 22, 2009 at 11:07 AM CEST #
I'm not sure that calling successive getters (programmatically or through JXPath) could be considered a good practice, you should better tweak your jpql "join fetch" per usecase basis.
Gesendet von John am October 22, 2009 at 11:21 AM CEST #
@John,
absolutely right. This is only an option - not a good practice.
I used this "hack" in some projects to solve the lazy loading options afterwards - it worked.
thanks for your feedback!,
adam
Gesendet von Adam Bien am October 22, 2009 at 11:56 AM CEST #
Claus,
WebBeans aka Java Contexts and Dependency Injection or Seam are great, but not always applicable. Sometimes it is necessary to expose a ServiceFacade to remote clients. In this case you will have to think about a lazy loading strategy.
thanks!,
adam
Gesendet von Adam Bien am October 22, 2009 at 06:08 PM CEST #
why JXPath? Is it simpler to use as the XPath functionality of the JDK? Both are 1.0.
Gesendet von michael am October 22, 2009 at 06:23 PM CEST #
@Michael,
you can use XPath to traverse Java-classes?
greeting from the ICE,
adam
Gesendet von Adam Bien am October 22, 2009 at 10:59 PM CEST #
hehe, i see ;)
Gesendet von michael am October 22, 2009 at 11:17 PM CEST #
While this is ok to avoid LazyInitExceptions, it's horrible when it comes to performance. Each call of a getter to an uninitialized entity will result in a separate SELECT to the database.
Check out this approach to generate JOINs by simple (xpath like) strings:
http://bwinterberg.blogspot.com/2009/09/hibernate-preload-pattern.html
The idea behind is quite similiar but with this approach, you'll see just one joined SELECT instead of many.
Gesendet von Benjamin Winterberg am October 23, 2009 at 02:28 PM CEST #
We have added DataExtents to cleanly abstract different "areas" of an object graph. It works nicely with DAOs, e.g.
myPerson = myDao.findById(myPk, myExtent);
where myExtent describes what needs to be loaded. Example extent definitions (e.g. on the DAO):
DataExtent
fileWithoutContentExtent =
new DataExtent(File.class)
.with("name", "lastModified", "fileSize", "mimeType");
DataExtent
fullFileExtent =
new DataExtent(File.class).
with("name", "content", "lastModified", "fileSize", "mimeType");
More details:
http://philhoser.blogspot.com/2008/11/dataextends-to-controll-lazy-loading.html
Gesendet von Philipp Oser am October 24, 2009 at 01:29 PM CEST #