Adam Bien's Weblog

Thursday Oct 22, 2009

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]


Special Events: Java 8 with Java EE 7: "More Power with Less Code", 13th October, 2014 and Java EE 7: "Testing and Code Quality", 14th October, 2014

A book about rethinking Java EE Patterns

Comments:

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

Posted by Claus Hausberger on October 22, 2009 at 01:07 PM 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.

Posted by John on October 22, 2009 at 01:21 PM 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

Posted by Adam Bien on October 22, 2009 at 01:56 PM 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

Posted by Adam Bien on October 22, 2009 at 08:08 PM CEST #

why JXPath? Is it simpler to use as the XPath functionality of the JDK? Both are 1.0.

Posted by michael on October 22, 2009 at 08:23 PM CEST #

@Michael,

you can use XPath to traverse Java-classes?

greeting from the ICE,

adam

Posted by Adam Bien on October 23, 2009 at 12:59 AM CEST #

hehe, i see ;)

Posted by michael on October 23, 2009 at 01:17 AM 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.

Posted by Benjamin Winterberg on October 23, 2009 at 04: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

Posted by Philipp Oser on October 24, 2009 at 03:29 PM CEST #

Post a Comment:
  • HTML Syntax: NOT allowed
realworldpatterns.com
...the last 150 posts
...the last 10 comments
Links
License