Well, we have a solution that seems to be working right now (at least for now) that also handles many to one proxies.
Essentially, working with a given root object and using some recursion we look at what the user wants to lazy load.
So imagine the following if you will.
Root Object with a 1-M collection of As, on each A there is a M-1 proxied B and then off the B a 1-M collection of Cs (need a scorecard yet?)
A user might say for a given root object give me A.B.C.
So there pass the instance of the RootObject and a string "A.B.C"
The first thing the method does is opens up a session, clones the object (due to problems with interceptor) and then calls session.update(rootObject) - we were using LockMode at first but that wasn't working for dirty objects.
Once the clone of the rootObject is locked into the session we can then start looking at the properties that the user requested.
If we are just asking for the collection of As (or even if it is a proxy) it is pretty simple. We simply call the following method
Code:
private void initialize(Object objectToInitialize, Session session) throws Exception {
//if the object is already initialized then don't bother with it
if (!Hibernate.isInitialized(objectToInitialize)) {
//need to set the session on the object so that it can be initialized
if (objectToInitialize instanceof PersistentCollection) {
PersistentCollection persistentCollection = (PersistentCollection) objectToInitialize;
persistentCollection.setCurrentSession((SessionImplementor) session);
} else if (objectToInitialize instanceof HibernateProxy) {
HibernateProxyHelper.getLazyInitializer((HibernateProxy) objectToInitialize).setSession((SessionImplementor) session);
}
Hibernate.initialize(objectToInitialize);
}
}
This allows us to set the object to be tied to the current session, we can then call initialize on it so that it gets loaded up.
The last step would be to set the initialized hibernate object back onto the original root object (not the cloned one).
The root object then goes back to the client and we can perform this logic multiple times. (Took us a while to work out the kinks)
Now, the A.B.C scenario is a bit more complex but by using recursion we can reuse all of the logic from the simple A case.
Essentially, the method looks and sees there is more than one property being requested in a chain (by the A.B.C notation).
It then takes the A and initializes it, then takes B.C and passes it back to the method itself recursively for each element in the collection. Where each A in the collection is the new root object and then B.C are the properties to load for A.
Same thing happens when it sees the B (i.e. passes B recursively as the rootObject and C as the property and initializes B).
It goes all the way down to C, calls the initialize on C, sets it on B.
Once A.B.C is initialized the whole works is set back on the original rootObject that the Client passed in and everyone goes home happy.
Now, if you can follow all of that I didn't obfusicate well enough ;)