Google App Engine (GAE) のサーブレットで Java Google Drive API を使用しようとしていますが、サーブレットが Eclipse の (localhost) サーバーに最初にロードされるときにNoClassDefFoundErrorを取得します。
テストとして、サーブレットで GoogleClientSecrets クラスのインスタンスを作成しようとしました。Eclipse コンパイラは文句を言いません。Java ビルド パス google-api-client-1.16.0- に C:\app\gDrive\libs**google-api-client-1.16.0-rc.jar** があります。 rc.jar には、 GoogleClientSecrets を含むパッケージcom.google.api.client.googleapis.auth.oauth2が含まれています。
Eclipse の Google プラグインの (localhost) サーバーは通常どおりロードされます。サーブレット クラスが最初にロードされるとき (サーブレット クラスへの最初の要求が行われるとき)、NoClassDefFoundError が発生します。GoogleClientSecrets への参照をコメント アウトすると、サーブレットは正常に動作します。
google-api-client-1.16.0-rc.jar は、外部 jar ファイルとして Eclipse -> Java Build Path -> Libraries リストにあります。[注文とエクスポート] タブで「チェック」マークが付いています (これは、jar ファイルを war ファイルにパッケージ化する必要があることを意味すると思います。サーバー環境で使用できる必要があります。
実行時に GAE でこれらのクラスを使用する際に何らかの制限はありますか? サーバーまたはサーブレットのクラスローダーのクラスパスに違いはありますか? (スタンドアロンの Java アプリケーションでは、Google ドライブにアクセスするためのコードは正常に機能します (つまり、その Java アプリケーション環境に必要なすべての jar があります。サーバーに奇妙な点があります (Jetty サーバーだと思います))。
DevAppServer がクラスを見つける方法を更新する
(Mark Doyle が指摘しているように) DevAppServer のクラス ローディング スキームは、DevAppServer コード自体をロードするために使用されるクラス ローディング スキームとは、webapp によって使用されるクラスをロードするために完全に異なります。また、Web アプリのクラス ローディング スキームは、通常の Eclipse プロジェクトのビルドパスではありません。処理する。(わかりやすくするために、ここでこれらすべてがどのように機能するかを文書化しているので、もう一度見つけることができます。)
調べてみると、Web アプリケーションのクラスをロードするときに、DevAppServer が Google クラスの「IsolatedAppClassLoader」を呼び出していることがわかります (各 Web アプリケーションのクラスのロードを互いに分離するためです。IsolatedAppClassLoader.loadClass() はDevAppServerClassLoader .loadClass() を呼び出します)。ケース) は最終的にそのスーパークラス java.lang.ClassLoader.loadClass() を呼び出し、この場合は java.net.URLClassLoader.findClass() を呼び出し、URLClassPath.getResource() を呼び出します。ここで多くの作業が開始されます。
URLClassPath.getResource() には、URLClassPath オブジェクトにリストされている各ローダーを取得する「for」ループがあります。この場合、sun.misc.URLClassPath$JarLoader (URLClassPath のサブクラス) のすべてのインスタンスである、URLClassPath に 17 (!7) 個のローダーがあります。-- これらは DevAppServer jar のようです。クラスが見つからないため、ClassNotFoundException が返されます (このレベルで)。
IsolatedAppClassLoaderはこれを繰り返します (理由はわかりませんが、今度は URLClassLoader オブジェクト (run() メソッド) を直接使用します。PrivilegedExceptionAction.run() に関する何か??)) いずれにせよ、URLClassPath (の匿名サブクラスから) URLClassLoader ??) は URLClassPath.getResource() を実行します (この IsolatedAppClassLoader インスタンスは URLClassLoader のサブクラスです!)。IsolatedAppClassLoader インスタンスには、21 個のローダーを持つ「ucp」フィールド (URLClassPath サブオブジェクト) が含まれています。
1 つ目は、url ファイルを含む FileLoader インスタンス (URLClassPath のサブクラス) です: /C:/eclip/webAppName/war/WEB-INF/classes/ -- これは、war/WEB 内のすべての個々のクラスを見つける場所です。 -INF/classes ディレクトリ。残りの 20 個のローダーはすべて JarLoader ローダーです。その 15 のうち、プロジェクトの war/WEB-INF ディレクトリにある 15 の .jar ファイルに対応します。残りの 5 つの JarLoader インスタンスは次のとおりです。
file:/C:/app/eclipse/plugins/com.google.appengine.eclipse.sdkbundle_1.8.2/appengine-java-sdk-1.8.2/lib/impl/agent/appengine-agentruntime.jar!/ file:/ C:/app/eclipse/plugins/com.google.appengine.eclipse.sdkbundle_1.8.2/appengine-java-sdk-1.8.2/lib/tools/jsp/repackaged-appengine-jakarta-jstl-1.1.2.jar !/ ファイル:/C:/app/eclipse/plugins/com.google.appengine.eclipse.sdkbundle_1.8.2/appengine-java-sdk-1.8.2/lib/tools/jsp/repackaged-appengine-jakarta-standard- 1.1.2.jar!/ ファイル:/C:/app/eclipse/plugins/com.google.appengine.eclipse.sdkbundle_1.8.2/appengine-java-sdk-1.8.2/lib/tools/jsp/repackaged-appengine -jasper-jdt-6.0.29.jar!/ ファイル:/C:/app/eclipse/plugins/com.google.appengine.eclipse.sdkbundle_1.8.2/appengine-java-sdk-1.8.2/lib/opt/ tools/appengine-local-endpoints/v1/appengine-local-endpoints.jar!/
なぜこれらがリストに載っているのかわかりませんが、おそらく Jetty の標準的なものでしょうか?