Expand my Community achievements bar.

failed to lazily initialize a collection of role

Avatar

Level 3
I am using Spring and Hibernate 3. The problem I am running
into is lazy loading, the session is getting blasted when Flex
tries to create an object that has sets.



<set name="loans" inverse="true" lazy="true">

<key>

<column name="amortization_type_id" />

</key>

<one-to-many class="com.gcloans.dao.hibernate3.Loan"
/>

</set>



I don't want to have lazy="false" for memory issues. Any
ideas.
7 Replies

Avatar

Level 3
Hi Ken,



Do you have an associated data service destination for the
Loan entity type that is also marked as lazy? If this property
isn't marked as lazy in the data service config a deep traversal is
done because we don't maintain long running Hibernate sessions.



When you state that the session is getting blasted what
exactly are you experiencing?



Best,

Seth

Avatar

Level 3
Seth -



Thanks for the reply. I have tried a number of things,
including setting the lazy="true" on all of the associated data
service destinations. I have even gone as far as commenting out my
sets for each definition - my current config. The problem I am
having is I am getting one of the various Lazy Load failures which
refer to a none existant session.



for example:

Aug 22, 2006 4:54:02 PM
org.hibernate.LazyInitializationException <init>

SEVERE: could not initialize proxy - the owning Session was
closed

org.hibernate.LazyInitializationException: could not
initialize proxy - the owning Session was closed

at
org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:53)

at
org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:84)

at
org.hibernate.proxy.CGLIBLazyInitializer.intercept(CGLIBLazyInitializer.java:134)

at
com.gcloans.dao.hibernate3.Contact$$EnhancerByCGLIB$$aa099d5f.toString(<generated>)

at java.lang.String.valueOf(String.java:2615)

at
flex.messaging.util.ToStringPrettyPrinter.prettifyComplexType(ToStringPrettyPrinter.java:82)

at
flex.messaging.util.BasicPrettyPrinter.internalPrettify(BasicPrettyPrinter.java:93)

at
flex.messaging.util.ToStringPrettyPrinter.prettifyComplexType(ToStringPrettyPrinter.java:163)

at
flex.messaging.util.BasicPrettyPrinter.internalPrettify(BasicPrettyPrinter.java:93)

at
flex.messaging.util.BasicPrettyPrinter.prettify(BasicPrettyPrinter.java:55)

at
flex.messaging.util.ToStringPrettyPrinter.prettify(ToStringPrettyPrinter.java:57)

at flex.messaging.log.Logger.log(Logger.java:376)

at flex.messaging.log.Logger.log(Logger.java:352)

at flex.messaging.log.Logger.debug(Logger.java:132)

at
flex.messaging.services.RemotingService.serviceMessage(RemotingService.java:124)

at
flex.messaging.MessageBroker.routeMessageToService(MessageBroker.java:548)

at
flex.messaging.endpoints.AbstractEndpoint.serviceMessage(AbstractEndpoint.java:302)

at
flex.messaging.endpoints.amf.MessageBrokerFilter.invoke(MessageBrokerFilter.java:93)

at
flex.messaging.endpoints.amf.LegacyFilter.invoke(LegacyFilter.java:156)

at
flex.messaging.endpoints.amf.SessionFilter.invoke(SessionFilter.java:46)

at
flex.messaging.endpoints.amf.BatchProcessFilter.invoke(BatchProcessFilter.java:67)

at
flex.messaging.endpoints.amf.SerializationFilter.invoke(SerializationFilter.java:130)

at
flex.messaging.endpoints.AMFEndpoint.service(AMFEndpoint.java:164)

at
flex.messaging.MessageBrokerServlet.service(MessageBrokerServlet.java:340)

at
javax.servlet.http.HttpServlet.service(HttpServlet.java:802)

at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)

at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)

at
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)

at
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)

at
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)

at
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)

at
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)

at
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)

at
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)

at
org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)

at
org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)

at
org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)

at
org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)

at java.lang.Thread.run(Thread.java:595)



From what I can tell on the web I need to set up an
OpenSessionInViewInterceptor, I am just not sure how to properly.



Avatar

Level 2
Hi Ken,



I think the issue is with our debug logging code (Message.*).
We have some "pretty printer" logic which is trying to recursively
dump out the state of any arguments and return values to the
RemoteObject call. For your Hibernate entity object, this means it
is trying to access the state of some properties which have not
been initialized yet because they are lazily loaded. Since this is
all happening after the remote object call has returned, the
session is closed.



If you can modify the code of your hibernate entity class to
add your own custom toString method, it will skip this recursive
pretty printer logic. Just makes ure your toString does not fetch
the state of properties that have not been loaded (I usually have
mine print the ids of the referenced objects for single valued
relationships and you probably want to just forgo printing anything
for collections since hibernate will not have fetched any state for
them).



Sorry for the problems... this pretty printer thing was added
late in the game. I had kind of wanted an option to turn it on so
it is off by default but we did not get that in.



Jeff Vroom

Avatar

Level 3
Jeff -



Thanks for the info. I have been banging my head against the
wall on this one. I will try and see what happens. I will post my
result here. Thankfully I had added my own abstraction layer so
this should be pretty easy.



Ken

Avatar

Level 3
Jeff -



That does not appear to be the problem or resolution to the
problem. My toString method never even gets called.



Ken

Avatar

Level 2
Hi Ken,



My apologies, I think I was off by one-level in my
understanding of the problem. From looking at the stack trace more
carefully, I believe the issue is that you do a query on hibernate
to return a Contact instance. It is not that this instance has
properties which point to objects which are not initialized, but
that it is not initialized itself. When the debug logging tries to
fetch the Contact instance to call its toString method, it is
failing to retrieve the "real" populated Contact instance.



This problem is more structural since even if you turn off
debugging, the state of that object has not been fetched so this
would just move the error elsewhere. I think that in this case, you
just have to initialize the Contact instance in your RemoteObject
before returning it. Otherwise, it is just a hollow shell which
only has the "id" of the Contact - there is no data there yet. This
might be a simple matter of trying to fetch some property of the
Contact before it gets returned. There is also the
"Hibernate.initialize(<your-obj>)" method which you could try
as well to do this more generically.



The other problem I think you'll run into though is that the
class name of the returned object is not what you'd expect. Instead
of it being:



com.gcloans.dao.hibernate3.Contact



it is actually:




com.gcloans.dao.hibernate3.Contact$$EnhancerByCGLIB$$aa099d5f



This is hibernate's generated class wrapper which fetches the
state of the real contact the first time you try to access it.
Unfortunately this wrapper class messes up the RemoteClass mapping
if you are trying to map this to a concrete type in ActionScript.
It may also mess up the serialization even if you are expecting
that to come over as a weak typed "Object" in ActionScript (I
believe it at least has an extra "implementation" property). If you
do run into those problems, you could try using the solution we
added for "Data Management Services". You'd have to simply add this
line to some code which gets initialized before your remote object
gets returned:



import org.hibernate.proxy.HibernateProxy;

import flex.messaging.io.PropertyProxyRegistry;

import flex.data.assemblers.HibernatePropertyProxy;

....


PropertyProxyRegistry.getRegistry().register(HibernateProxy.class,
new HibernatePropertyProxy());





This basically means that whenever AMF encounters an object
which implements the "HibernateProxy" interface, it uses this
HibernatePropertyProxy class to help serialize that object. Instead
of serializing the CGLIB wrapper class, it gets the implementation
class from underneath that and serializes that object. This does
assume that object has already had its public properties
initialized so make sure to access some property of your Contact
instance before closing the hibernate session.



Finally, I believe it is also possible to configure hibernate
so it does not use CGLIB generated wrappers if this is getting too
complicated. I hope this helps,



Jeff

Avatar

Level 3
Thanks Jeff -



What I ended up doing was to set the lazy="true" on all my
many-to-one and one-to-one definitions. I erroroniously thought
that the problem was with my set definitions. If I get to spot, and
I am sure I will, where I need to retrieve that deep relationship,
I will try what you mentioned.



Thanks again.



Ken