-->
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: Tough reflection problem - occasional failure
PostPosted: Sun Jul 10, 2005 10:53 am 
Beginner
Beginner

Joined: Tue Aug 10, 2004 8:59 am
Posts: 47
Hibernate version: 3.0

Occasionally I have problems invoking hibernate entities through reflection. Sometimes the underlying JDK throws

java.lang.IllegalArgumentException: object is not an instance of declaring class

I have written a class called PropertyMapping which invokes my entity's property setter method. In the following example I am trying to set a simple String property called "name" on an entity of class TextView, and though it almost always works, it does fail occasionally, indicated by the exception above.

What happens is this:

1. I look up my entity's setName method like this:
writeMethod =
myTextView.getClass().getMethod(writeMethodName, propertyCarrierClass);

2. I invoke the write method like this
writeMethod.invoke(myTextView, object);

3. Sometimes, not always, Java throws
java.lang.IllegalArgumentException:
object is not an instance of declaring class

as if to indicate that the entity is not the entity from which I looked up the method.

I have sourrounded my method invokation with the following code:
try {...}
catch(IllegalArgumentException exception) {
throw new SystemFailure(
"\nUnable to write a value property \"" +
property.getName() + "\" to an entity property:\n" +
"Entity class: \"" + (myTextView == null ? null : myTextView.getClass().getName()) + "\"\n" +
"Entity method name: \"" + (writeMethod == null ? null : writeMethod.getName()) + "\"\n" +
"Method belongs to class: \"" + writeMethod.getDeclaringClass().getName() + "\"\n" +
"Method parameter type: \"" + writeMethod.getParameterTypes()[0].getName() + "\"\n" +
"Object to be written: \"" + property.getObject() + "\"\n" + "Object type: \"" + (property.getObject() == null ? null : property.getObject().getClass().getName()) + "\"\n",
exception
);
}

And this code outputs the following

Unable to write a value property "name" to an entity property:
Entity class: "dk.rockit.puls.server.entity.website.content.text.TextView"
Entity method name: "setName"
Method belongs to class: "dk.rockit.puls.server.entity.website.content.text.Text
View$$EnhancerByCGLIB$$46db9118"
Method parameter type: "java.lang.String"
Object to be written: "H°jre kolonnes visning"
Object type: "java.lang.String"

Here is the exception, which is thrown occasionally:

Caused by: java.lang.IllegalArgumentException: object is not an instance of declaring class
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
sorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at dk.rockit.puls.server.value.manager.propertyMapping.PrimitiveMapping.
write(PrimitiveMapping.java:118)
at dk.rockit.puls.server.value.manager.propertyMapping.PrimitiveMapping.
differentiate(PrimitiveMapping.java:150)
at dk.rockit.puls.server.value.manager.AbstractValueManager.differentiat
e(AbstractValueManager.java:403)
...


So, as you can see, I look up a method on an entity which is being proxied by CGLIB and then somehow this makes the reflection fail. In the example above I am looking up the method "setName" on a class called "TextView", which apparantly is being proxied by CGLIB as

dk.rockit.puls.server.entity.website.content.text.TextView$$EnhancerByCGLIB$$46db9118

and then the reflection mechanism below is unable to operate correctly.

Has anyone got a clue to what could be wrong here and / or why this only fails occasionally and not all the time?

Any hints would be highly appreciated.

Randahl


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jul 10, 2005 11:29 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
You must find method declared by "TextView" class to use it with both types, your method is declared by proxy. Proxy is an instance of "TextView", but "TextView" is not an instance of TextView$$EnhancerByCGLIB$$46db9118 ( proxy extends entity class ) .


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jul 10, 2005 1:06 pm 
Beginner
Beginner

Joined: Tue Aug 10, 2004 8:59 am
Posts: 47
Alright - I see why this could be a problem... I will try that. Still, I wonder why this only happens sometimes and not all the time - could that have something to do with how and when the proxies are used and how and when my entity is used? I though the proxy was always used, thus I expected the error would occur either always or not at all.

Randahl


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jul 10, 2005 1:27 pm 
Senior
Senior

Joined: Thu May 12, 2005 11:40 pm
Posts: 125
Location: Canada
It only happens sometimes because some Hibernate calls return proxies while others return initialized instances. Instead of trying to understand which do which (as that is really a Hibernate implementation detail), I've simply tried to make my reflective code work regardless of whether it is passed a proxy or the real deal. To help with this, I have a method like this in my base domain model object:

public Class getEntityClass()
{
if (Enhancer.isEnhanced(getClass()))
return getClass().getSuperclass();

return getClass();
}

I call this method instead of getClass() whenever I might otherwise be calling getClass() on my domain model objects.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 11, 2005 3:35 am 
Beginner
Beginner

Joined: Tue Aug 10, 2004 8:59 am
Posts: 47
I see your point.

I noticed you are using the Enhancer.isEnhanced method - since it is not part of my own imports I suppose this is a CGLIB method. Consequently I have implemented this instead:

private Class<Entity> findRealEntityClass(Entity entity) {
Class<Entity> realEntityClass;
if(entity instanceof HibernateProxy) {
//the entity is proxied by CGLIB inner class
realEntityClass =
(Class<Entity>) entity.getClass().getSuperclass();
}
else {
//the entity is of a regular entity class
realEntityClass = (Class<Entity>) entity.getClass();
}
return realEntityClass;
}

Which uses the Hibernate marking interface HibernateProxy instead of the CGLIB method - would you not agree that this is a more appropriate, more abstract way of detecting proxies than using the CGLIB method? Just in theory, I think the above might work if Hibernate changing proxying technology, whereas using a CGLIB method would not. Would you not aggree?


Randahl


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 11, 2005 9:41 am 
Senior
Senior

Joined: Thu May 12, 2005 11:40 pm
Posts: 125
Location: Canada
Yeah, that's probably better, I will change my code. Now we just have to figure out a way to get rid of that horrible, horrible cast :)


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 11, 2005 10:47 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
see Hibernate.getClass(Object entity)


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 11, 2005 1:33 pm 
Senior
Senior

Joined: Thu May 12, 2005 11:40 pm
Posts: 125
Location: Canada
Ah, even better.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 12, 2005 8:46 am 
Beginner
Beginner

Joined: Tue Aug 10, 2004 8:59 am
Posts: 47
According to the docs of the Hibernate.getClass method it instantiates a proxy as a side effect. The docs do not say if that is a time consuming process. I think I will stick to the method I posted - it does not have this side effect.

Randahl


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.