David Blevins wrote:

On May 21, 2008, at 5:04 PM, Dain Sundstrom wrote:

I think Rick may be able to provide more insight than me given his work on vm class loading, but I'll take a shot at this one....

I think the difference between the two exceptions is based on when the VM discovers it has an invalid class. The second exception shows us that the bad class is openejb.org.superbiz.cmp2.MovieBean, which is a class we generated directly using ASM. In "Style 1", I think something about the code in EjbHomeProxyHandler was causing the VM to perform a full verify on the class (FWIU the vm only verifies what is needs to improve VM startup time). Was EjbHomeProxyHandler doing something like scanning all the Method objects? Anyway, in "Style 1", for some reason the vm didn't have (or didn't provide) additional information about which class was having the error, which based on my coding experience is a pretty common situation. In "Style 2", the vm clearly knows what's going on and tells us everything necessary to fix the problem.

In the long term, we could catch this problem with the verifier or if they turn that off, we could just fill in a do nothing implementation.

Huh. Not sure. We're talking about zero code change anywhere in anything (even the test case) other than the following patch.
I'm not sure I'm buying the verifier answer either. The verifier will fully validate a class before allowing it ever to be used for any purpose. Any path that will cause a failure will make the class non-usable....and result in a verifier error, not something like a class cast exception. I'm thinking perhaps the problem might be you're getting a ClassCastException on the throwable line itself. The line

   cause = new EJBException(re.getMessage(), (Exception) detail);

will cause a ClassCastException because detail is an instance of AbstractMethodError, which is not a subclass of Exception. Unfortunately, you can't just remove the (Exception) cast, because that's the type specified on the constructor. It looks like the initClause() form is the only way to get what you want out of this.

Rick


Index: src/main/java/org/apache/openejb/core/ivm/EjbHomeProxyHandler.java
===================================================================
--- src/main/java/org/apache/openejb/core/ivm/EjbHomeProxyHandler.java (revision 655683) +++ src/main/java/org/apache/openejb/core/ivm/EjbHomeProxyHandler.java (working copy)
@@ -210,7 +210,7 @@
if (cause instanceof RemoteException && interfaceType.isLocal()) {
                 RemoteException re = (RemoteException) cause;
                 Throwable detail = (re.detail != null) ? re.detail : re;
- cause = new EJBException(re.getMessage(), (Exception) detail); + cause = new EJBException(re.getMessage()).initCause(detail);
             }
             throw cause;
             /*

I'm not sure how class verification, etc. could be affected. Taking a fresh look at this, the ClassCastException part of Style 1 looks awfully fishy...

Yea, that's it.  Can't believe I missed it.

-David





-dain

On May 21, 2008, at 4:52 PM, David Blevins wrote:

There seems to be some major difference between these two styles of EJBException creation. I ran into this working on a CMP example I intend to use for the whole CMP+JPA->JPA merging logic. The real error is that I forgot to implement "setEntityContext" which is an easy mistake to make as the CMP2 bean class is abstract and compiles just fine without it. I got the first stack trace below, which is useless, and decided on a whim to tweak EjbHomeProxyHandler line 213 to the second style shown below. I was and am shocked at the difference in the stack trace.

[Style 1] throw new EJBException(re.getMessage(), (Exception) detail);
Yields:
java.lang.ClassCastException: java.lang.AbstractMethodError
at org.apache.openejb.core.ivm.EjbHomeProxyHandler._invoke(EjbHomeProxyHandler.java:213) at org.apache.openejb.core.ivm.BaseEjbProxyHandler.invoke(BaseEjbProxyHandler.java:274)
    at org.superbiz.cmp2.$Proxy26.create(Unknown Source)
    at org.superbiz.cmp2.MoviesTest.test(MoviesTest.java:51)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at com.intellij.rt.execution.junit2.JUnitStarter.main(JUnitStarter.java:32)


[Style 2]   throw new EJBException(re.getMessage()).initCause(detail);
Yields:

javax.ejb.EJBException: The bean encountered a non-application exception.; nested exception is: java.lang.AbstractMethodError: openejb.org.superbiz.cmp2.MovieBean.setEntityContext(Ljavax/ejb/EntityContext;)V at org.apache.openejb.core.ivm.EjbHomeProxyHandler._invoke(EjbHomeProxyHandler.java:213) at org.apache.openejb.core.ivm.BaseEjbProxyHandler.invoke(BaseEjbProxyHandler.java:274)
    at org.superbiz.cmp2.$Proxy26.create(Unknown Source)
    at org.superbiz.cmp2.MoviesTest.test(MoviesTest.java:51)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at com.intellij.rt.execution.junit2.JUnitStarter.main(JUnitStarter.java:32) Caused by: java.lang.AbstractMethodError: openejb.org.superbiz.cmp2.MovieBean.setEntityContext(Ljavax/ejb/EntityContext;)V at org.apache.openejb.core.cmp.CmpContainer.setEntityContext(CmpContainer.java:318) at org.apache.openejb.core.cmp.CmpContainer.createEJBObject(CmpContainer.java:592) at org.apache.openejb.core.cmp.CmpContainer.invoke(CmpContainer.java:250) at org.apache.openejb.core.ivm.EjbHomeProxyHandler.create(EjbHomeProxyHandler.java:267) at org.apache.openejb.core.ivm.EjbHomeProxyHandler._invoke(EjbHomeProxyHandler.java:158)
    ... 21 more


Able to verify the stack trace behavior is this way in both intellij and maven. Obviously the stack trace for style #1 completely obfuscates the problem which is itself a big problem.

Anyone have any idea, what causes this difference?

Needless to say, I'll shortly be switching all our code over....

-David






Reply via email to