GAEjでDWR - NoClassDefFoundError対処法 -

以下のページを参考にして、GAEjでDWR使ったAjaxアプリを作ろうとしました。

指定されたページは存在しません

Version 3.rc1のdwr.jarをダウンロードし、web.xmlやdwr.xmlをした後、

アプリを実行すると以下のスタックトレースが発生して、起動に失敗しました。

2009/12/23 11:52:18 com.google.apphosting.utils.jetty.JettyLogger warn
警告: failed dwr-invoker
java.lang.NoClassDefFoundError: javax.swing.event.EventListenerList is a restricted class. Please see the Google  App Engine developer's guide for more details.
at com.google.appengine.tools.development.agent.runtime.Runtime.reject(Runtime.java:51)
at org.directwebremoting.impl.DefaultScriptSessionManager.<init>(DefaultScriptSessionManager.java:534)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.google.appengine.tools.development.agent.runtime.Runtime.newInstance_(Runtime.java:112)
at com.google.appengine.tools.development.agent.runtime.Runtime.newInstance(Runtime.java:132)
at org.directwebremoting.impl.DefaultContainer.addParameter(DefaultContainer.java:102)
at org.directwebremoting.impl.StartupUtil.setupDefaults(StartupUtil.java:499)
at org.directwebremoting.impl.StartupUtil.setupDefaultContainer(StartupUtil.java:245)
at org.directwebremoting.impl.StartupUtil.createAndSetupDefaultContainer(StartupUtil.java:188)
at org.directwebremoting.servlet.DwrServlet.createContainer(DwrServlet.java:97)
at org.directwebremoting.servlet.DwrServlet.init(DwrServlet.java:64)
at org.mortbay.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:433)
at org.mortbay.jetty.servlet.ServletHolder.doStart(ServletHolder.java:256)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40)
at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:612)
at org.mortbay.jetty.servlet.Context.startContext(Context.java:139)
at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1218)
at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:500)
at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:448)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:117)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:117)
at org.mortbay.jetty.Server.doStart(Server.java:217)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40)
at com.google.appengine.tools.development.JettyContainerService.startContainer(JettyContainerService.java:188)
at com.google.appengine.tools.development.AbstractContainerService.startup(AbstractContainerService.java:120)
at com.google.appengine.tools.development.DevAppServerImpl.start(DevAppServerImpl.java:217)
at com.google.appengine.tools.development.DevAppServerMain$StartAction.apply(DevAppServerMain.java:162)
at com.google.appengine.tools.util.Parser$ParseResult.applyArgs(Parser.java:48)
at com.google.appengine.tools.development.DevAppServerMain.<init>(DevAppServerMain.java:113)
at com.google.appengine.tools.development.DevAppServerMain.main(DevAppServerMain.java:89)
(長いのでcause分は略)

javax.swing.event.EventListenerListはGAEjで使えないよ、と。

自分で実装した範囲内でjavax.swing.event.EventListenerListは使ってないので、

DWRの実装で使われてるんだろうなーと目星をつけ、

ソースコードをダウンロードしたり、

jarを解体してみたり、

ググってみたりと色々してみたんですが、

なかなか情報が無く苦労しました・・・。

原因

org.directwebremoting.impl.DefaultScriptSessionManager」。

web.xmlで指定したサーブレット「org.directwebremoting.servlet.DwrServlet」のinitメソッド内で

アプリケーションを初期設定してるのですが、この初期化サイクルの中で、

dwr.jar内にある「defaults.properties」内のクラスの完全修飾名からインスタンス生成をしている箇所がありました。

defaults.properties」で指定されているクラスを全て調べたところ、

エラー原因となっているjavax.swing.event.EventListenerListを使っているクラスは、

org.directwebremoting.impl.DefaultScriptSessionManager」だけでした。

このクラスの中で、javax.swing.event.EventListenerListをインスタンスフィールドで使っている為に、

指定されたクラスのインスタンスを生成する際に、NoClassDefFoundErrorがスローされる、というわけですねー。

対処

org.directwebremoting.impl.DefaultScriptSessionManager」は、

defaults.properties」で「org.directwebremoting.extend.ScriptSessionManager」キ ーで指定されています。

この設定を上書きすればいいわけです。

defaults.properties」は「org.directwebremoting」パッケージに配置されているので、

自分のローカルのソースフォルダに「org.directwebremoting」パッケージを作成、

dwr.jar内から取り出した「defaults.properties」の下記の箇所を変えて、配置しました。

#org.directwebremoting.extend.ScriptSessionManager: org.directwebremoting.impl.DefaultScriptSessionManager
org.directwebremoting.extend.ScriptSessionManager: org.directwebremoting.impl.TransientScriptSessionManager

TransientScriptSessionManager」は「DefaultScriptSessionManager」同様、

org.directwebremoting.extend.ScriptSessionManage」インターフェイスを実装しています。

DefaultScriptSessionManager」では、javax.swing.event.EventListenerListを以下のメソッ ドで使用していまが、

TransientScriptSessionManager」では以下のpublicメソッドは空実装、protectedメソッドは未定義です。

  • public void addScriptSessionListener(ScriptSessionListener li)
  • public void removeScriptSessionListener(ScriptSessionListener li)
  • protected void fireScriptSessionCreatedEvent(ScriptSession scriptSession)

ちなみに、「DefaultScriptSessionManager」は上記のメソッド以外でも、

java.util.concurrent」パッケージのクラス群を利用しています。

org.directwebremoting.ScriptSessionを複数スレッドで監視するためだと思いますが、詳細は不明・・・

正直言うと、「DefaultScriptSessionManager」を「TransientScriptSessionManager」に変えた結果、

何が違ってくるのかはっきりしていないのですが、とりあえずコレでGAEj上でDWRが動くようになります。

もっと簡単に設定変えれてもいいとは思いますが、DWRの設定に関する情報が少なくて断念。

もうちょっと情報あると、実務でも使いやすくなるとは思うのですが・・・

簡単にAjaxアプリを作れるだけに残念です。

このエントリーをはてなブックマークに追加
comments powered by Disqus