org.apache.http.impl.io.DefaultHttpRequestWriterFactory 处的 NoSuchFieldError 实例

NoSuchFieldError INSTANCE at org.apache.http.impl.io.DefaultHttpRequestWriterFactory

java version "1.7.0_71" 
Gradle 2.1

你好,

UPDATE:

依赖项

gradle dependencies | grep httpcore
|    +--- org.apache.httpcomponents:httpcore:4.3.3
|    +--- org.apache.httpcomponents:httpcore:4.3.3
|    +--- org.apache.httpcomponents:httpcore:4.3.3
|    +--- org.apache.httpcomponents:httpcore:4.3.3
|    |         |    |         |    +--- org.apache.httpcomponents:httpcore:4.1 -> 4.3.3
|    +--- org.apache.httpcomponents:httpcore:4.3.3
|    |         |    |         |    +--- org.apache.httpcomponents:httpcore:4.1 -> 4.3.3

这是否意味着我的 4.1 是 link 到 4.3.3 的软版本?看起来很奇怪,因为当我打印出 class 加载器正在加载的内容时,它似乎加载了 4.3.3:/home/steve/.gradle/caches/modules-2/files-2.1/org.apache.httpcomponents/httpcore/4.3.3/f91b7a4aadc5cf486df6e4634748d7dd7a73f06d/httpcore-4.3.3.jar 似乎很奇怪。

当我尝试 运行 我的 httpClient 时,我一直收到这个错误。一切编译正常。

java.lang.NoSuchFieldError: INSTANCE
        at org.apache.http.impl.io.DefaultHttpRequestWriterFactory.<init>(DefaultHttpRequestWriterFactory.java:52

我的代码很简单,删除了不重要的代码以保持小:

public class GenieClient {
    private CloseableHttpClient mClient;

    public GenieClient() {
        ClassLoader classLoader = GenieClient.class.getClassLoader();
        URL resource = classLoader.getResource("org/apache/http/message/BasicLineFormatter.class");
        log.log(Level.INFO, "resource: " + resource);

        mClient = HttpClientBuilder.create().build();
    }

    public int sendRequest() {   
        int responseCode = -1;

        try {
            HttpResponse response = mClient.execute(new HttpPost("http://www.google.com"));
            responseCode = response.getStatusLine().getStatusCode();
        }
        catch(IOException ex) {
            log.log(Level.SEVERE, "IOException: " + ex.getMessage());
        }

        return responseCode;
    }
}

我从 classLoader 得到的输出是这样的:

INFO: resource: jar:file:/home/steve/.gradle/caches/modules-2/files-2.1/org.apache.httpcomponents/httpcore/4.3.3/f91b7a4aadc5cf486df6e4634748d7dd7a73f06d/httpcore-4.3.3.jar!/org/apache/http/message/BasicLineFormatter.class

我正在使用 gradle 作为我的构建工具,并在我的 build.gradle 文件中设置了这样的依赖项:

dependencies {
    compile 'org.apache.httpcomponents:httpclient:4.3.6'
}

我也试过包含以下httpcore,但仍然得到同样的错误:

compile 'org.apache.httpcomponents:httpcore:4.4'

一切正常,只有当我 运行 我的 httpClient,

非常感谢您的任何建议,

用 -verbose:class 启动你的 jvm,它会显示哪个 class 从哪里加载。

我过去在两种情况下遇到过这样的问题:

  1. 您正在加载的其中一个 jar 有一个带有 Classpath 子句的清单,它引用了错误版本的 httpcore。

  2. 您 运行 在某个容器(tomcat 或某物)中,带有自己的 class 加载器,并且加载了一些 classes,例如通过来自不同罐子的容器。

我也不认为您显示 class 资源的代码有效,因为它明确使用了 GenieClient 的 classloader。可能使用 BasicLineFormatter.class.getClassloader() 会给出不同的结果。 但最好尝试 -verbose:class.

很明显,您的类路径中有一些旧版本的 BasicLineFormatter,其中包含 DEFAULT 字段而不是 INSTANCE。参见 e.g

但是您的类加载器报告您正在使用 httpcore-4.3.3,并且您的 Gradle 依赖树支持这一点。

所以您似乎还有一些其他 JAR,其中包含 BasicLineFormatter 的旧版本。您可能需要检查依赖项 JAR,看看它是否在其中。尝试 jar tf *.jar | grep 'BasicLineFormatter' 查看可能涉及哪些 JAR。

另外,这个可能是相关的。我查看了您的标签,您似乎做了一些 Android 开发。因此,以下 Stack Overflow question 可能会引起您的兴趣:

即使这不是确切的问题,它也显示了即使您拥有正确的 httpcore 依赖项,您也可能有一个旧的 BasicLineFormatter 闲逛。

org.apache.httpcomponents:httpcore:4.1 -> 4.3.3表示4.1是请求的版本,通过冲突解决被解析为4.3.3。执行类似 gradle -q dependencyInsight --configuration compile --dependency httpcore 的操作应该会让您对此有更多了解。

您应该检查构建输出,看看您的应用实际打包了哪些 jar。此外,使用一些文件管理器 运行 通过构建输出(当然包括存档)搜索 BasicLineFormatter.class,这应该会给你一个明确的答案什么 jars 包含这个 class 的什么版本.

如果只有一个版本 (4.3.3),这一定意味着另一个版本来自 运行安装您的应用程序的容器。解决这个问题的方法取决于容器。

如果你确实找到了多个版本,你可以尝试在项目中全局排除对httpcore的传递依赖(user guide的第51.4.7章)。

If you define an exclude for a particular configuration, the excluded transitive dependency will be filtered for all dependencies when resolving this configuration or any inheriting configuration.

似乎 BasicLineFormatter 得到了它的静态 INSTANCE in 4.3-beta1 link and link

  1. 查找版本低于 4.3 的 httpcore
  2. 从引用的库中删除旧版本的 httpcore jar。