1

我有两个 Eclipse 项目(在同一个工作区中),一个是运行码头实例的标准 java 项目。另一个是 GWT 项目。GWT 项目(在文件系统上)作为 web 应用程序存在于 java 项目中,并由 jetty (xml) 配置加载。

我在调试时都通过 eclipse 运行,首先我将 jetty 服务器作为常规 java 应用程序(localhost:8080)启动,然后将 GWT 项目作为“Web 应用程序(在外部服务器上)”启动。

一切都很好,除了尝试投射课程时。在某些情况下,我会得到 java.lang.ClassCastException。经过数小时的调试,我确定这是由于使用了两个单独的类加载器,每个类加载器一个。

我认为这源于在 servlet 上下文中创建的对象和不是在 servlet 上下文中创建的对象。

我创建了一个测试来证明这一点。假设从传入请求到 servlet 调用以下方法,参数 instanceOfClassA 在 servlet 请求处理程序的某处创建并传递给此方法:

public void calledFromServlet(ClassA instanceOfClassA){

    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
    // systemClassLoader is sun.misc.Launcher$AppClassLoader@45a877

    Object classA1 = new ClassA();
    ClassLoader loader1 = classA1.getClass().getClassLoader();
    // loader1 is is WebAppClassLoader=GWTProject@b98fe1


    ClassLoader loader2 = instanceOfClassA.getClass().getClassLoader();
    // loader2 is sun.misc.Launcher$AppClassLoader@45a877

    ClientA request = (ClassA)instanceofClassA; // java.lang.ClassCastException!
}

如您所见(希望),在当前上下文中创建的对象由 WebAppClassLoader=GWTProject@b98fe1 加载,在 servlet 上下文中创建的对象(在其他地方)由系统加载程序 sun.misc.Launcher$AppClassLoader@45a877 加载。

因此,当我尝试将在 servlet 上下文中创建的对象强制转换为当前上下文中的同一个类时,我得到了 ClassCastException。

不用说这真的毁了我的一周,我无法解决这个问题,因为我需要能够投射物体。

有没有人经历过这种情况并有解决方案?

更新(1 月 5 日凌晨 2:24):我尝试使用 Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader()) 强制当前线程的类加载器。还是不行。

更新(1 月 6 日下午 1:09——Thomas Boyer)

似乎有两个感兴趣的线程正在运行,一个我的断点位于:

Thread [38] (Suspended (breakpoint at line 53 in CollaborationSocketListener))  
CollaborationSocketListener.onMessage(String) line: 53  
WebSocketConnectionRFC6455$WSFrameHandler.onFrame(byte, byte, Buffer) line: 845 
WebSocketParserRFC6455.parseNext() line: 359    
WebSocketServletConnectionRFC6455(WebSocketConnectionRFC6455).handle() line: 235    
SelectChannelEndPoint.handle() line: 606    
SelectChannelEndPoint$1.run() line: 46  
QueuedThreadPool.runJob(Runnable) line: 603 
QueuedThreadPool$3.run() line: 538  
Thread.run() line: 662  

另一个属于 gwt-dev 启动器:

 com.google.gwt.dev.DevMode at localhost:37240  
    Thread [main] (Running) 
Thread [Thread-0] (Running) 
Daemon Thread [Thread-1] (Running)  
Daemon Thread [UnitWriteThread] (Running)   
Daemon Thread [Timer-0] (Running)   
Daemon Thread [Code server listener] (Running)  
Daemon Thread [com.google.gwt.thirdparty.guava.common.base.internal.Finalizer] (Running)    
Daemon Thread [com.google.inject.internal.util.$Finalizer] (Running)    
Daemon Thread [Code server for freshgwtp from Mozilla/5.0 (X11; Linux i686)     AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.47 Safari/536.11 on http://localhost:8080/FreshGWTP.html?gwt.codesvr=127.0.0.1:9997 @ h`"*x.nukanE_ke_] (Running)   

被调用的方法是为了响应传入的消息到 servlet (WebSocket servelet)。相关代码在这里:

public void onMessage(String serRequest) {

        // Create a request here to show that we can cast anything created in this context
    Object uFakeRequest = new ClientConnectRequest("someSite", new Client("SomeClient"));

    // This cast works fine
    ClientConnectRequest fakeRequest = (ClientConnectRequest)uFakeRequest;

            // Now I build the same object from a serialized object using a "deserializer" instantiated elsewhere (Note what it is instantiated does not seem to make a difference
    Object uRequest = streamer.fromString(serRequest);

            // ClassCastException
    ClientConnectRequest request = (ClientConnectRequest)uRequest;

    CollaborationSite site = siteManager.getOrCreateSite(request.getSiteID());

    site.onRequestRecieved(con, request);
}

“streamer”是一个 gwt-streamer(有关详细信息,请参阅 google 代码),我尝试在 servelet init() 中实例化它,以及在此方法中内联,并通过 Guice 注入。我总是得到相同的类转换异常。

原因是streamer的类加载器是系统类加载器,而当前方法中的类加载器是GWT-Dev类加载器。

** 更新(1 月 5 日下午 2:36)更多混乱 **

为了分离类加载器之间的冲突,我启动了两个单独的 eclipse 实例,一个启动了 jetty 应用程序,另一个启动了 gwt-dev 模式(在外部服务器上)。仍然得到同样的错误。

我不明白为什么 GWT 认为应该在外部服务器的服务器端代码上处理类加载......

4

0 回答 0