HTTP要求を他のURLに送信するために Mashape Unirest を使用するMaven Javaプロジェクトがあります。現在、Unirestを使用して通常のHTTPリクエストを送信する統合テスト( TestNG を使用)を作成しています。Maven経由で(フェイルセーフプラグインを介して)統合テストを実行すると、リクエストが正常に送信されますしかし、Eclipseを介して統合テストを実行しようとすると、次のエラーが引き続き発生します。
FAILED: getCurrentTimeTest
Java.lang.NoSuchFieldError: INSTANCE
at org.Apache.http.impl.io.DefaultHttpRequestWriterFactory.<init>(DefaultHttpRequestWriterFactory.Java:52)
at org.Apache.http.impl.io.DefaultHttpRequestWriterFactory.<init>(DefaultHttpRequestWriterFactory.Java:56)
at org.Apache.http.impl.io.DefaultHttpRequestWriterFactory.<clinit>(DefaultHttpRequestWriterFactory.Java:46)
at org.Apache.http.impl.conn.ManagedHttpClientConnectionFactory.<init>(ManagedHttpClientConnectionFactory.Java:72)
at org.Apache.http.impl.conn.ManagedHttpClientConnectionFactory.<init>(ManagedHttpClientConnectionFactory.Java:84)
at org.Apache.http.impl.conn.ManagedHttpClientConnectionFactory.<clinit>(ManagedHttpClientConnectionFactory.Java:59)
at org.Apache.http.impl.conn.PoolingHttpClientConnectionManager$InternalConnectionFactory.<init>(PoolingHttpClientConnectionManager.Java:487)
at org.Apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.Java:147)
at org.Apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.Java:136)
at org.Apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.Java:112)
at org.Apache.http.impl.client.HttpClientBuilder.build(HttpClientBuilder.Java:726)
at com.mashape.unirest.http.options.Options.refresh(Options.Java:41)
at com.mashape.unirest.http.options.Options.<clinit>(Options.Java:27)
at com.mashape.unirest.http.HttpClientHelper.prepareRequest(HttpClientHelper.Java:141)
at com.mashape.unirest.http.HttpClientHelper.requestAsync(HttpClientHelper.Java:80)
at com.mashape.unirest.request.BaseRequest.asStringAsync(BaseRequest.Java:56)
at ...
基本的なJavaアプリケーションスクリプトを使用して、このエラーを再現することもできます。
pom.xmlファイルで使用している依存関係が、以下に示すように最新かつ最大であることを確認しました。
<dependency>
<groupId>com.mashape.unirest</groupId>
<artifactId>unirest-Java</artifactId>
<version>1.3.5</version>
</dependency>
<dependency>
<groupId>org.Apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.2</version>
</dependency>
<dependency>
<groupId>org.Apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
<version>4.0</version>
</dependency>
<dependency>
<groupId>org.Apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.3.2</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20140107</version>
</dependency>
<dependency>
<groupId>org.Apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.3.2</version>
</dependency>
Eclipseにダウンロードしたソースファイルと ApacheのHttpcore Github repo の両方から、BasicLineFormatter.Java
のソースコードもチェックアウトしました。 Githubリポジトリで、4.3.xブランチとトランクブランチに対してINSTANCE
フィールドが定義されていますが、4.2.xなどの古いブランチでは定義されていないことに注意してください。ただし、実際にプロジェクトで4.3.2
バージョンを使用しているため、BasicLineFormatter
の最新バージョンを持つHttpcoreのJARファイルを使用する必要があります。私のプロジェクトにあるMaven依存関係JARファイルに基づいて、プロジェクトのダウンストリーム依存関係として指定された古いバージョンではなく、これらのApache依存関係の最新バージョンを実際に使用していることを知っています。
Mashape Unirest Java:Java.lang.NoClassDefFoundError and this)など、この問題に関する他のさまざまなSOFおよびブログ投稿を確認しました。ブログ投稿も ですが、彼らはすべてAndroidのNoSuchFieldError問題の解決について話しているようです。しかし、私はスタンドアロンJava Androidアプリケーションではありません。
この問題のトラブルシューティング方法の決定に途方に暮れています。誰も私が何をする必要があるか考えていますか?
テストケースを示す代わりに、この問題の再現の図を単純な1行のライナーJavaアプリケーションに減らします。問題はJava特定の1つのテストだけでなく、Eclipseを介して実行されるアプリケーションまたはテストケース:
System.out.println(Unirest.get("http://www.google.com").asStringAsync().get().getBody());
通常、これはGoogleホームページのHTMLを印刷するはずですが、代わりにNoSuchFieldErrorスタックトレースを取得します。
問題は、AWS SDK(Elastic Beanstalk用に開発しているため、クラスパス上にある)に競合するJARファイルがあったことです。 Olegのソリューションを使用して(BTWに感謝)、ユニットテストで次の出力を印刷しました。
jar:file:/some/path/aws-Java-sdk/1.7.1/third-party/httpcomponents-client-4.2.3/httpcore-4.2.jar!/org/Apache/http/message/BasicLineFormatter.class
AWS SDKが競合しないように、クラスパスを再配置する必要があります。
この問題のもっともらしい説明は、クラスパスに古いバージョンのHttpCoreがあることです(火星の緑の男性が空飛ぶ円盤からリモートでコンピューターをいじる可能性も考慮したい場合を除きます)。
このスニペットをコードに追加して、クラスが取得するjarを見つけることができます。これは、そもそもそのjarがクラスパスにある理由を見つけるのに役立つかもしれません。
ClassLoader classLoader = MyClass.class.getClassLoader();
URL resource = classLoader.getResource("org/Apache/http/message/BasicLineFormatter.class");
System.out.println(resource);
これは基本的に、私の場合、jarはローカルのMavenリポジトリに存在し、Mavenによってクラスパスに追加された可能性が高いことを教えてくれます
jar:file:/home/oleg/.m2/repository/org/Apache/httpcomponents/httpcore/4.3.1/httpcore-4.3.1.jar!/org/Apache/http/message/BasicLineFormatter.class
前のコメントですでに述べたように、それは主にhttpcore
jarの競合するバージョンが原因で、静的フィールドINSTANCEがversions > 4.3.1
のBasicLineFormatter
クラスに追加されます。依存関係にあるhttpcore
jarの最新バージョンですが、他の(下位)バージョンのjarが取得される可能性が高いです。
そのため、最初に間違ったjarが取得されることを確認するには、次のコード行を使用します-
ClassLoader classLoader = <Your Class>.class.getClassLoader();
URL resource = classLoader.getResource("org/Apache/http/message/BasicLineFormatter.class");
System.out.println(resource);
これがjarの下位バージョンを出力すると、httpcore jarの下位バージョンを選択していることが確認されます(プロジェクトの他の依存関係にある可能性があります)。
ソリューション-
次のMaven/Gradle依存関係を依存関係リストの先頭に追加します(または、競合を引き起こした他のプロジェクトの依存関係の上に)
<dependency>
<groupId>com.mashape.unirest</groupId>
<artifactId>unirest-Java</artifactId>
<version>1.4.5</version>
</dependency>
<dependency>
<groupId>org.Apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.1</version>
</dependency>
<dependency>
<groupId>org.Apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.4.1</version>
</dependency>
私はunirestを使用して同じ例外に直面しました:
Java.lang.NoSuchFieldError: INSTANCE
at org.Apache.http.impl.io.DefaultHttpRequestWriterFactory.<init>(DefaultHttpRequestWriterFactory.Java:52)
at com.mashape.unirest.http.options.Options.refresh(Options.Java:55)
at com.mashape.unirest.http.options.Options.<clinit>(Options.Java:36)
そして、それはDefaultConnectionKeepAliveStrategy.INSTANCE;
によるものであり、競合するjarは私のクラスパスでApache-httpcomponents-httpclient.jar
であることがわかりました。同様の例外に直面している人を助けるためにこの投稿を追加する
私はこの例外を受け取りました:Caused by: Java.lang.NoSuchFieldError: INSTANCE
溶液:
これは、クラスパスに2つの異なるバージョンクラスがある場合に発生します…。 […]、そのため、最初にそのクラス(クラスの1つのバージョン)を見つけ、そのクラスをクリックして、ビルドパスを選択し、次にビルドパスから削除をクリックします。
aWS SDKを使用している場合、このエラーは依存関係の不一致が原因で発生します。このエラーを回避するには、次の手順を実行します。
これで問題が解決しました