These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 13 posts ] 
Author Message
 Post subject: hibernate proxies on remote machine with network ClassLoader
PostPosted: Mon Mar 16, 2009 12:51 pm 
Newbie

Joined: Mon Mar 16, 2009 5:38 am
Posts: 6
Need help with Hibernate? Read this first:
http://www.hibernate.org/ForumMailingli ... AskForHelp

Hibernate version 3.4.0.GA:


I am working on a swing / web application bridge for a swing client. As a communication layer I am using something I would call RMI over HTTP (serialized class data is transfered through HTTP). The swing client needs to be small because it will be invoked using Java WebStart. This is the reason why I cannot include all hiberante dependencies in the client JAR and I am forced to use network class loading. The problem appear when I try to deserialize hiberante proxies.

This is what I get on the client side:

Code:
Caused by: org.hibernate.HibernateException: Javassist Enhancement failed: ...the package...Studio
   at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.getProxy(JavassistLazyInitializer.java:109)
   at org.hibernate.proxy.pojo.javassist.SerializableProxy.readResolve(SerializableProxy.java:78)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:597)
   at java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1061)
   at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1762)
   at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
   at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
   at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
   at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
   at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
   at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
   at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
   at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
   at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
   at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
   at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
   at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
   at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
   at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
   at ...the package.....JavaNativeDeserializer.deserializeObject(JavaNativeDeserializer.java:46)
   ... 8 more
Caused by: java.lang.ClassFormatError: Invalid code attribute name index 0 in class file javassist/util/proxy/ProxyFactory
   at java.lang.ClassLoader.defineClass1(Native Method)
   at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
   at ...the package....ServerAwareClassLoader.load(ServerAwareObjectInputStream.java:192)
   at ...the package....ServerAwareClassLoader.loadClass(ServerAwareObjectInputStream.java:106)
   at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
   at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.getProxy(JavassistLazyInitializer.java:95)
   ... 30 more



I am sure that transfer layer works fine. No class data gets corrupted (md5 calculated on both ends matches).

I need to mention that if I include all dependencies in the client jar file everything works fine.

I suspect that there are some class loading issues assicuated with javaasist. Do I need to do something special to load the javaasist classes?
If I cannot make it work can anyone suggest some other solution?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 18, 2009 9:22 am 
Senior
Senior

Joined: Tue Aug 01, 2006 9:24 pm
Posts: 120
Can you tell me more about how you are serializing the objects.

This is actually a common problem as you might be serializing the wrong object. As you probably figured out by now hibernate wraps it's objects in proxies.

This can sometimes be compensated by simply casting your object to the correct object or even if you can pass to the serializer app the type of class it is, then pass it the parent of the proxy which should be your original class.

I can't say I have seen your specific exception because I haven't. But It doesn't seem like you would want the javassist proxy anyway so I would get that out ofyour pojo before you serialize it.

There is a lot of information on this topic see if this helps at all.

http://blog.jeremymartin.name/2008/02/j ... jects.html

_________________
Please rate my replies as I need points for all of my questions also.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 23, 2009 9:53 am 
Newbie

Joined: Mon Mar 16, 2009 5:38 am
Posts: 6
Thanks for reply!

I use native Java serialization via ObjectOutputStream on the server side and ObjectInputStream on client side. The resolveClass(ObjectStreamClass desc) of ObjectInputStream has been overridden to allow network class loading. It cannot be simplier :)

When I started this project the first solution was to remover proxy classes and external dependencies just before the serialization takes place. It worked but the performance was not acceptable and I decided that network class loading will be better solution).

I'm really curious what am I doing wrong and why everything works fine if I have hibenate-core.jar (with dependencies) attached on client side...

Any further suggestions?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 23, 2009 11:59 am 
Senior
Senior

Joined: Tue Aug 01, 2006 9:24 pm
Posts: 120
The hibernate-core is needed because of the proxy classes. If you remove the proxy classes then you won't need the libraries. I think you actually only need 2 libraries, javassist and hibernate-core but don't qoute me on this.

There are a lot of solutions to your problem the simplest might just be to remove lazy fetch from your mappings/annotations. This of course would bring back the whole tree. Depending on your use this might work fine though. I think it's lazy=false that you would want. On this page this is also a lazy="no-proxy" that might be some help.

http://www.hibernate.org/315.html

The other thing you can try is Hibernate.initialize(object o); This will initialize the object, but I think the proxy is still attached.

I have never actually used native java serialization before myself. Most of the time I am always converting to json or xml. Perhaps this might be another path to look down. It certainly makes your data more flexible to be used by quite a few types of non-java apps. Libraries like castor and xstream have mechanisms to avoid the proxy classes.

_________________
Please rate my replies as I need points for all of my questions also.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 23, 2009 12:18 pm 
Newbie

Joined: Mon Mar 16, 2009 5:38 am
Posts: 6
I was thinking about xml and xstreem but this would need much more to code both on client and server side. The app will have only swing clients so the simplicity that native Java serialization gives is what I want :). The performance is also not so bad .

Eager fetching is not an option here. In my opinion its really bad design pattern to use eager fetching everywhere.

The no-proxy solution would be great but... I use hiberante as JPA implementation and as far as I know I can't use no-proxy in my entities... Or maybe I'm wrong and I can somehow?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 23, 2009 1:32 pm 
Senior
Senior

Joined: Tue Aug 01, 2006 9:24 pm
Posts: 120
Quote:
Eager fetching is not an option here. In my opinion its really bad design pattern to use eager fetching everywhere.

It would be a bad design pattern but in your case, you are fetching the entire tree anyway. The lazy fetching strategy is used only when you don't need some data. For instance if you have people and addresses and you are always accessing both then you would fetch the people and their address's eagerly. Doing one query is better than doing 2 in a situation like this. It all depends on your use and how often you are accessing the children of your object.

You are going to have to initialize your lazily fetched items if you are going to acceess them anyway, because you will lose your session on the client side( you can't fetch a lazily loaded object once your on the client unless you reassociate it with a new session).

I think you need to evaluate what data you actually need to pass to your swing client and figure out what is the most efficient manner.

As far as the no-proxy solution I have never used this, but if your using hibernate you should have a way to use it. Unless your looking for compatibility with toplink or some other implementation.

_________________
Please rate my replies as I need points for all of my questions also.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 23, 2009 2:14 pm 
Newbie

Joined: Mon Mar 16, 2009 5:38 am
Posts: 6
I know how lazy loading works :). In my entities I have almost everything marked as lazy and when I need some lazy fetched data i make a query with join fetch - so I have always one query when fetching data and never fetch to much. This is the optimal way to use ORM and it works well for me.

Moreover I never initialize proxies. If I have proxy somewhere it always will be uninitialized. Thats why no-proxy would be great for me. I'll do some reading on this and see what can I do with it!


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 23, 2009 3:04 pm 
Senior
Senior

Joined: Tue Aug 01, 2006 9:24 pm
Posts: 120
Code:
so I have always one query when fetching data and never fetch to much.


This isn't true because if you query for people and fill your entities. Then decide you want to see your addresses that's 2 queries done at seperate times. If you will always need both your addresses and people then you setup your annotations/mappings so that you don't lazy fetch. If you do this correctly you will execute one query for both addresses and people.

for instance if you lazy load addresses this is what you will get
Select p.name, p.id from people
then
Select a.name, a.id from address a where a.id = ?

Where as
Select p.name, p.id, a.street, a.id from people p join address a on a.id = p.fkaddress

Could be faster and less expensive then continually making requests to the database.

The first example could be blown up exponentially depending on your datamodel.

Granted the second example can also be slower in some situations but it all depends on your app.

_________________
Please rate my replies as I need points for all of my questions also.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 23, 2009 6:04 pm 
Newbie

Joined: Mon Mar 16, 2009 5:38 am
Posts: 6
You didn't understand my point. Join fetch allows me to fetch people and addresess using only one query. In jpql it looks like this:

Code:
select p from People p join fetch p.addresses where...


And I have only one query. When I need only data from People entity i simply use hibernate api to get it and do not initialize addresses collection...


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 23, 2009 6:28 pm 
Senior
Senior

Joined: Tue Aug 01, 2006 9:24 pm
Posts: 120
Ok sorry,
Just wondering are you still getting the proxies when you use that query? You might want to check it in your debugger before you call the getter on the child just check to see if it's your real object or the proxy.

The proxies are non-existant when lazy fetch is off.

There is no magic bullet for this, you will either have to manually initialize and copy your data to new objects, turn lazy fetch off or re-evaluate your data model.

I am also curious as to why your exception doesn't have a classNotFoundError is that exception run with the hibernate libraries on the client side.

And did you see these posts

http://forum.hibernate.org/viewtopic.php?p=2407563
https://jira.jboss.org/jira/browse/JASSIST-28
http://www.jboss.org/index.html?module= ... ic&t=83199

_________________
Please rate my replies as I need points for all of my questions also.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 25, 2009 4:26 pm 
Newbie

Joined: Mon Mar 16, 2009 5:38 am
Posts: 6
Ok, I solved the problem... kind of :/. It seems that turining lazy loading off for @ManyToOne relationship solved the problem. As I mentioned earlier I don't like lazy loading and I would prefer to solve the root of the problem and not use a workarond.

Anyway if someone knows how to fix this please comment.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 25, 2009 4:50 pm 
Senior
Senior

Joined: Tue Aug 01, 2006 9:24 pm
Posts: 120
Turning it off is not a workaround. It's a design decision. You decide what objects should or should not be loaded. It's not hibernate's job to figure out what objects you need.

Not really sure why a lot of people think changing lazy loading is a hack!

_________________
Please rate my replies as I need points for all of my questions also.


Top
 Profile  
 
 Post subject: Re: hibernate proxies on remote machine with network ClassLoader
PostPosted: Wed Jul 07, 2010 2:43 pm 
Newbie

Joined: Mon May 31, 2010 7:29 am
Posts: 5
Old post, I know... But does anyone know if I can use @LazyToOne(LazyToOneOption.NO_PROXY) with JPA??


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 13 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.