[GLASSFISH-17281] javax.ejb.AsyncResult in Remote interfaces with DTOs generates ClassCastException on client Created: 08/Sep/11  Updated: 23/Nov/12

Status: In Progress
Project: glassfish
Component/s: orb
Affects Version/s: 3.1.1_b12
Fix Version/s: None

Type: Bug Priority: Critical
Reporter: vins4java Assignee: Harshad Vilekar
Resolution: Unresolved Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Windows Vista SP2
JDK 1.6.0_26


Attachments: Zip Archive AsyncTestCase-src.zip     File module-a-ear.ear     File module-b-ear.ear    
Tags: 3_1_2-exclude, asynchronous, ejb31

 Description   

Scenario:

  • 2 ear apps say A and B (module-a-ear and module-b-ear)
  • each ear has contains an ejb-jar (module-a-ejb and module-b-ejb)
  • A's ejb exposes remote interface with an @Asyncronous method
  • the asyncronous method returns a serializable DTO (ADto)
  • both A and B have the same copy of A's ejbClient in their ear's root (module-a-ejbClient.jar)

when a method of B calls a remote asynch method on A, the call is perfomed but when Future<ADto> is done, on module-b-ejb side a ClassCastException is thrown when invoking:
ADto wrappedDto = futureDto.get();

EJB 3.1 specs don't make dinstinction about local or remote interface for @Asynchrouse annotation.They also don't put any limitation in Future<V>, so Data Transfer Objects (serializable) must be supported, right?

In order to have a very simple test case (didn't want to create JEE appclient..) I've annotated module-b-ejb as WebService so that you can call module-b-ejb method via glassfish admin gui webservice tester. You can find a stacktrace in the attached zip file. I also provided the 2 deployable ear files.

IMHO:
Debugging on client side (using eclipse debugger) I had a look at classloader of the ADto instance received from A: it's the A's classloader, not B's! It's strange because I tried also to change method in the "old traditional" synch fashion( public ADto doAsync() ) and on client side the returning ADto correclty comes from A's classloader. Does this help?



 Comments   
Comment by vins4java [ 14/Oct/11 ]

any update on this issue?

Comment by Cheng Fang [ 14/Oct/11 ]

I was able to reproduce it on trunk build. Stack trace is the same as in your attachment(except slightly different line numbers):

        at com.sun.ejb.containers.BaseContainer.processSystemException(BaseContainer.java:5219)
        at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:5117)
        at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4905)
        at com.sun.ejb.containers.WebServiceInvocationHandler.invoke(WebServiceInvocationHandler.java:207)
        at $Proxy234.testIt(Unknown Source)
        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 org.glassfish.webservices.InvokerImpl.invoke(InvokerImpl.java:82)
        at org.glassfish.webservices.EjbInvokerImpl.invoke(EjbInvokerImpl.java:82)
        at com.sun.xml.ws.server.InvokerTube$2.invoke(InvokerTube.java:150)
        at com.sun.xml.ws.server.sei.EndpointMethodHandler.invoke(EndpointMethodHandler.java:261)
        at com.sun.xml.ws.server.sei.SEIInvokerTube.processRequest(SEIInvokerTube.java:100)
        at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:641)
        at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:600)
        at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:585)
        at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:482)
        at com.sun.xml.ws.api.pipe.helper.AbstractTubeImpl.process(AbstractTubeImpl.java:116)
        at org.glassfish.webservices.MonitoringPipe.process(MonitoringPipe.java:142)
        at com.sun.xml.ws.api.pipe.helper.PipeAdapter.processRequest(PipeAdapter.java:119)
        at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:641)
        at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:600)
        at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:585)
        at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:482)
        at com.sun.xml.ws.api.pipe.helper.AbstractTubeImpl.process(AbstractTubeImpl.java:116)
        at com.sun.enterprise.security.webservices.CommonServerSecurityPipe.processRequest(CommonServerSecurityPipe.java:212)
        at com.sun.enterprise.security.webservices.CommonServerSecurityPipe.process(CommonServerSecurityPipe.java:144)
        at com.sun.xml.ws.api.pipe.helper.PipeAdapter.processRequest(PipeAdapter.java:119)
        at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:641)
        at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:600)
        at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:585)
        at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:482)
        at com.sun.xml.ws.server.WSEndpointImpl$2.process(WSEndpointImpl.java:314)
        at com.sun.xml.ws.transport.http.HttpAdapter$HttpToolkit.handle(HttpAdapter.java:608)
        at com.sun.xml.ws.transport.http.HttpAdapter.handle(HttpAdapter.java:259)
        at com.sun.xml.ws.transport.http.servlet.ServletAdapter.handle(ServletAdapter.java:162)
        at org.glassfish.webservices.Ejb3MessageDispatcher.handlePost(Ejb3MessageDispatcher.java:116)
        at org.glassfish.webservices.Ejb3MessageDispatcher.invoke(Ejb3MessageDispatcher.java:87)
        at org.glassfish.webservices.EjbWebServiceServlet.dispatchToEjbEndpoint(EjbWebServiceServlet.java:198)
        at org.glassfish.webservices.EjbWebServiceServlet.service(EjbWebServiceServlet.java:129)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:770)
        at org.glassfish.grizzly.servlet.ServletHandler$FilterChainImpl.doFilter(ServletHandler.java:985)
        at org.glassfish.grizzly.servlet.ServletHandler$FilterChainImpl.invokeFilterChain(ServletHandler.java:928)
        at org.glassfish.grizzly.servlet.ServletHandler.doServletService(ServletHandler.java:382)
        at org.glassfish.grizzly.servlet.ServletHandler.service(ServletHandler.java:335)
        at com.sun.enterprise.v3.server.HK2Dispatcher.dispatch(HK2Dispatcher.java:113)
        at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:236)
        at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:163)
        at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:161)
        at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:286)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:223)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:155)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:134)
        at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:78)
        at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:827)
        at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:103)
        at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:111)
        at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
        at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:131)
        at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:508)
        at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:488)
        at java.lang.Thread.run(Thread.java:680)
Caused by: java.lang.ClassCastException: module.a.ejb.ADto cannot be cast to module.a.ejb.ADto
        at module.b.ejb.BBean.testIt(BBean.java:36)
        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 org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1052)
        at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:1124)
        at com.sun.ejb.containers.BaseContainer.invokeBeanMethod(BaseContainer.java:5392)
        at com.sun.ejb.EjbInvocation.invokeBeanMethod(EjbInvocation.java:624)
        at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:790)
        at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:576)
        at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doAround(SystemInterceptorProxy.java:162)
        at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.aroundInvoke(SystemInterceptorProxy.java:144)
        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 com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:851)
        at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:790)
        at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:361)
        at com.sun.ejb.containers.BaseContainer.__intercept(BaseContainer.java:5364)
        at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:5352)
        at com.sun.ejb.containers.WebServiceInvocationHandler.invoke(WebServiceInvocationHandler.java:195)
        ... 60 more
Comment by Cheng Fang [ 18/Oct/11 ]

If you do not call future.isDone() on the client side, I suspect it will work.

Comment by vins4java [ 18/Oct/11 ]

unfortunately your suspect seems to be wrong: I get the same error even if I comment isDone() call on client ejb.
I've tested this modification on Glassfish 3.1.1-build12 ( on ubuntu with java-6-sun-1.6.0.26 ).
Did you try it with trunk version (3.2)?

Comment by Cheng Fang [ 19/Oct/11 ]

Looks like the payload didn't go thru proper marshalling and unmarshalling when both sides are colocated. It could also be some caching problem.

Comment by vins4java [ 25/Oct/11 ]

So you tried deploying each ear in two different JVMs (on the same physical machine or two different ones) and it worked, or you are supposing so? let me know if there's a way for me to help you to solve this problem. We are going to rely on this feature in short/med term...

Comment by Cheng Fang [ 25/Oct/11 ]

If the two modules are deployed into separate JVM, either same host or different hosts, that should work.
There is total separation of classloaders and so shouldn't be any CCE. What I found now is the DAO instance
on the ejb server side is different from the DAO instance on the client side, which means the serialization and
deserialization did happen. But the wrong classloader (the server side classloader) was used to reconstruct
the DAO on the client side. The client side application classloader should've been used for that.

Another complication is it is not the Java serialization protocol that's been used here. I'm trying to find out
how classloader is picked to copy objects by GlassFish corba and its related modules (see
glassfish.home/modules/glassfish-corba-orb.jar, pfl*.jar).

Again I think this issue only happens with all of the following:
remote async ejb method invocations;
both client and server modules are colocated in the same JVM;
some application class (e.g., business interface classes) are duplicated in both client and server modules

If you package client module and ejb module inside the same EAR file, and extract all shared classes into EAR/lib/xxx.jar,
without duplicating them in client and ejb modules, that should help avoid this CCE. I just tried it and worked.

Comment by Cheng Fang [ 04/Nov/11 ]

In org/glassfish/pfl/dynamic/copyobject/impl/ClassCopierOrdinaryImpl (in modules/pfl-dynamic.jar)
obj.getClass() is called to get the Class, which is then used to create a class copier, which in turn creates the constructor. It is hence associated with the class loader of the source object, not the target.

This part of the code is executed to copy all fields of a source object.

After changing to use thread context class loader in instead of
obj.getClass(), it worked without CCE. There could be other places the kind of changes are also necessary. Also not clear about the full implication or side effects.

Comment by Cheng Fang [ 04/Nov/11 ]

re-assign to orb team for further evaluation.

Comment by Harshad Vilekar [ 15/Dec/11 ]

Cheng and I exchanged email on this - and decided to target this issue post 3.1.2

Comment by juergenschmied [ 23/Nov/12 ]

I get this problem after upgrading from 3.1.2 to 3.1.2.2. A application that was working before is now broken with this error. Would it help do use a Future<ByteArrayOutputStream> an do serialization/deserialization by myself? It looks like this bug does not affect build-in classes.

Thanks!

Generated at Sat Mar 28 15:00:40 UTC 2015 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.