2021年4月28日 星期三

GWT使用Gson錯誤紀錄

使用Eclipse開發GWT的websocket應用時,發現如果我在Eclipse中用GWT內置的Jetty Server來啟動此應用,會拋出一個訊息是

Cannot call method public void 使用Annotation標記為ServerEndPoint 的類別完整路徑#中使用Annotation標記為OnOpen的函式((javax.websocket.Session, java.lang.String) with args: [org.eclipse.jetty.websocket.jsr356.JsrSession, java.lang.String]

的RuntimeException。

完整的錯誤訊息如下:

java.lang.RuntimeException: Cannot call method public void com.yabtogo.tth.server.chat.ChatEndpoint#onOpen(javax.websocket.Session, java.lang.String) with args: [org.eclipse.jetty.websocket.jsr356.JsrSession, java.lang.String]
at org.eclipse.jetty.websocket.common.events.annotated.CallableMethod.unwrapRuntimeException(CallableMethod.java:93)
at org.eclipse.jetty.websocket.common.events.annotated.CallableMethod.call(CallableMethod.java:75)
at org.eclipse.jetty.websocket.jsr356.annotations.OnOpenCallable.call(OnOpenCallable.java:54)
at org.eclipse.jetty.websocket.jsr356.annotations.JsrEvents.callOpen(JsrEvents.java:162)
at org.eclipse.jetty.websocket.jsr356.endpoints.JsrAnnotatedEventDriver.onConnect(JsrAnnotatedEventDriver.java:186)
at org.eclipse.jetty.websocket.common.events.AbstractEventDriver.openSession(AbstractEventDriver.java:227)
at org.eclipse.jetty.websocket.jsr356.endpoints.AbstractJsrEventDriver.openSession(AbstractJsrEventDriver.java:104)
at org.eclipse.jetty.websocket.common.WebSocketSession.open(WebSocketSession.java:420)
at org.eclipse.jetty.websocket.server.WebSocketServerConnection.onOpen(WebSocketServerConnection.java:72)
at org.eclipse.jetty.io.AbstractEndPoint.upgrade(AbstractEndPoint.java:185)
at org.eclipse.jetty.server.HttpConnection.completed(HttpConnection.java:345)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:436)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.LinkageError: loader constraint violation: loader (instance of com/google/gwt/dev/shell/jetty/JettyLauncher$WebAppContextWithReload$WebAppClassLoaderExtension) previously initiated loading for a different type with name "javax/websocket/RemoteEndpoint$Basic"
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at org.eclipse.jetty.webapp.WebAppClassLoader.findClass(WebAppClassLoader.java:510)
at com.google.gwt.dev.shell.jetty.JettyLauncher$WebAppContextWithReload$WebAppClassLoaderExtension.findClass(JettyLauncher.java:446)
at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:441)
at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:403)
at com.yabtogo.tth.server.chat.ChatEndpoint.lambda$0(ChatEndpoint.java:162)
at java.util.concurrent.CopyOnWriteArrayList.forEach(CopyOnWriteArrayList.java:891)
at java.util.concurrent.CopyOnWriteArraySet.forEach(CopyOnWriteArraySet.java:404)
at com.yabtogo.tth.server.chat.ChatEndpoint.broadcast(ChatEndpoint.java:159)
at com.yabtogo.tth.server.chat.ChatEndpoint.onOpen(ChatEndpoint.java:59)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.eclipse.jetty.websocket.common.events.annotated.CallableMethod.call(CallableMethod.java:70)
... 15 more

原本以為是使用的GWT SDK版本太舊,或是GWT SDK中嵌入的Jetty版本太舊,所以把GWT升級至2.9.0版,問題一樣出現。查了一下,GWT各版本內置的Jetty伺服器版本是:

GWT 2.5.1 -> jetty-6.1.11

GWT 2.6.1 -> jetty-8.1.12.v20130726

GWT 2.7.0 -> jetty-8.1.12.v20130726

GWT 2.8.2 -> jetty-9.2.14.v20151106

GWT 2.9.0 -> jetty-9.2.14.v20151106


再查一下jetty-9.2.14.v20151106版的Jetty有支援JSR 356啊,那是甚麼問題導致這個錯誤呢。

經過對專案架構檢視,當中用到的每一個第三方Library,發現程式中用到的Gson類別,原本規劃專案要加入Google的Gson Library包,但後來發現gwt-dev.jar中就有內置Gson類別,所以就直接使用,無另外安裝獨立的Gson Library包。心想會不會是Library相容性問題導致上述的例外錯誤呢,於是馬上加入獨立的Gson Library包,取代使用gwt-dev.jar內置的Gson類別(這部份要注意在專案的java Build Path中的Order and Export的設定,其中的獨立Gson Library包優先權須高於GWT SDK),重新用GWT內置的Jetty Server來啟動此專案應用,問題消失了。



沒有留言:

張貼留言