-->
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.  [ 9 posts ] 
Author Message
 Post subject: wrong interface cause ClassCastException
PostPosted: Mon Jan 12, 2004 2:25 pm 
Beginner
Beginner

Joined: Sun Sep 21, 2003 12:19 am
Posts: 40
I have the following mapping:

Code:

<class name="Parent" ... proxy="IParent"> ...</class>
<joined-subclass name="child1" ... extends="Parent" proxy="IChild1"/>
<joined-subclass name="child2" ... extends="Parent" proxy="IChild2"/>
<joined-subclass name="grandchild2" .... extends="child2" proxy="IGrandChild2"/>


I have a grandchild2 class which hibernate correctly persist it. When I try to search by using "find("from IParent"), it correctly instanciate grandchild2.

The problem is both Child1 and Child2 has same method called getB(). So after I cast the return object to IGrandChild2 then invoke the getB() method, it throws ClassCastException there.

It seems to be the proxy class CGLIBLazyInitializer's intercept call pass the proxy which contains 'IChild1' interface which grandchild2 doesn't not implement. Maybe it sees I used getB call then it will just radomly pickup the interface who has the method?

How can I ask hiberate choose IChild2 interface instead?

Thanks.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 12, 2004 3:49 pm 
Beginner
Beginner

Joined: Sun Sep 21, 2003 12:19 am
Posts: 40
Furthur debugging showing:

AbstractEntityPersister has a list of all the subclasses interfaces regardless what conrete class should be.

createProxy method in that class will take all the interfaces regardless if any of them are not superinterface.

I had a feeling that Hibernate should do a second round filter to populate correct interfaces after it instantiated conrete class.

Maybe a Hibernate bug?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 21, 2004 1:08 pm 
Beginner
Beginner

Joined: Sun Sep 21, 2003 12:19 am
Posts: 40
Looks like I am talking to myself here.:-(

Finally I get a chance to do furthur investigation around this problem.

Here is why, in getProxy code of CGLIBLazyInitializer,
Code:
   
final CGLIBLazyInitializer instance = new CGLIBLazyInitializer(
      persistentClass, interfaces, id, getIdentifierMethod, setIdentifierMethod, session);
final HibernateProxy proxy = (HibernateProxy) Enhancer.create(
            (interfaces.length==1) ?
                persistentClass :
                null,
            interfaces,
            instance
         );


When I use iterate() method to find this class, it only create an id and super-interface so it doesn't know all the subclass this particular id is implementing. So it passes every conceivable sub-interfaces to CGLib. So the proxy it returns contains all the interfaces regarless this id(instance) implemented or not. As I specified before, when invoking the method it could go to the wrong place.

Here is my hack to this problem since I don't think there is an esay way to re-narrow the interfaces after user get hold on this object's reference. Come think of it, it might be the IteratorImp's job to narrow the interface which should be doable.

Anyway, in intercept(....) method do the following will work:


Code:
  Object o = getImplementation();
  //find the real method to be invoking on instead of the wrong interface one
  Method implMethod = o.getClass().getMethod(method.getName(), method.getParameterTypes());
  return implMethod.invoke(o,args);
//this will break
//      return proxy.invoke( getImplementation(), args );



Please remember this is my work-around right now since it defeats the purpose of using CGLib doing byte code enhacement.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 21, 2004 2:59 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
This is all correct behavior for interface proxies. Try using concrete class proxies instead.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 21, 2004 5:29 pm 
Beginner
Beginner

Joined: Sun Sep 21, 2003 12:19 am
Posts: 40
I wish I could but :-(

We are using code by contract(interface) everywhere (reference are all using interface).

I have been looking a little bit more, if I can break the lazy contract in the iterator.next() which I hit the db at that time then I can narrow down to the correct proxies, it might works a little bit better(cleaner) than my previous posted 'hack'.

What do you think, Gavin? I know you might say no...:-(


Top
 Profile  
 
 Post subject: My problem
PostPosted: Wed May 26, 2004 9:49 am 
Newbie

Joined: Tue Apr 27, 2004 4:31 am
Posts: 13
Hello,

I have exact the same problem that I posted recently.

Gavin wrote:
Quote:
This is all correct behavior for interface proxies. Try using concrete class proxies instead.


I do not agree with the opinion that this is the correct behaviour. I cannot even imagine that this bug is to stay in the Hibernate implementation.

Is it subject to change in the near future, or should I try the solution (work around) as supplied by no_ejb?

Or do you have better options?

Erwin


Top
 Profile  
 
 Post subject: Work around
PostPosted: Thu May 27, 2004 7:28 am 
Newbie

Joined: Tue Apr 27, 2004 4:31 am
Posts: 13
Hello,

Another workaround I use right now is to define the methods that for example exist in both IPerson and IOrganisation in one super-interface, like IEmailable. Multiple inheritance is possible for interfaces and both are being derived from the IEmailable interface. The casting problem disappears, because the class will be casted to the unified IEmailable interface.

Greetings,
Erwin


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jul 03, 2004 2:06 pm 
Newbie

Joined: Thu May 06, 2004 4:25 pm
Posts: 13
Location: Prague, Czech Republic
Hi,
I've got the same problem. Has something changed since April? It seems to me more like a bug then a correct behavior. I thought I should use interface proxies for polymorphism, but this "bug" or "behavior" kills interface polymorphism.

What do you thin Gavin? How to use subclasses and proxies together?
Btw.: My ClassCastException is thrown when calling equals() or getId().

Thanks
Pavel


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 13, 2004 3:51 am 
Newbie

Joined: Wed Dec 10, 2003 8:40 pm
Posts: 9
We have definitely found that using the Interface style of lazy loading to be buggy when combined with inheritance mappings. We get intermittent errors when doing loads on base classes - occasionally the returned class is of the wrong type, resulting in a class cast exception when invoking a method on the subclass.

The following code seemed to work in getting consistent results however we are ripping out a lot of the inheritance stuff because it's causing too many headaches.

if(templateBasePrintHDO instanceof HibernateProxy){
HibernateProxy proxy = (HibernateProxy) templateBasePrintHDO;
LazyInitializer lz = HibernateProxyHelper.getLazyInitializer(proxy);
TemplateBasePrintHDO tbph = (TemplateBasePrintHDO)lz.getImplementation();
Hibernate.initialize(tbph.getPreviewImage());
}

The documentation could definetly be improved in this area - a guide on how to properly implement interface proxies with inheritance would be very useful. For example, things like whether the subclass interfaces need to implement the base interfaces etc


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 9 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.