Apache DefaultHttpClient 调用会导致“java.lang.RuntimeException: Stub!”

发布于 2024-09-12 17:23:15 字数 3284 浏览 7 评论 0原文

我正在尝试 Android 开发。我有一个将与 RESTful 资源交互的项目,我正在尝试弄清楚如何通过 HTTP 使用参数进行基本 GET 操作。从我读到的所有内容来看,共识似乎是支持 HTTPClient 而不是 HttpURLConnection。

我编写了一个包装类,其中的方法负责实例化关键对象以使用 HTTPClient 发出请求:

public String get() {  
    String responseString = null;

    HttpClient client = new DefaultHttpClient();
    HttpGet get = new HttpGet();
    try {
        get.setURI(new URI(this.baseURL()));
    } catch (URISyntaxException e1) {
        e1.printStackTrace();
    }

    HttpResponse response;

    try {
        response = client.execute(get);
        responseString = readResponse(response.getEntity());

        if(response != null) {
            System.out.println(responseString);
        }
    } catch(ClientProtocolException e) {
        e.printStackTrace();
    } catch(IOException e) {
        e.printStackTrace();
    }

    return responseString;

}

HttpClient client = new DefaultHttpClient(); 抛出以下异常:

java.lang.RuntimeException: Stub!
at org.apache.http.impl.client.AbstractHttpClient.<init>(AbstractHttpClient.java:5)
at org.apache.http.impl.client.DefaultHttpClient.<init>(DefaultHttpClient.java:7)
at org.rcindustries.appmap.RestClient.get(RestClient.java:54)
at org.rcindustries.appmap.test.functional.RestClientTest.shouldReturnSomeJSon(RestClientTest.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

每个示例我见过 HttpClient 使用类似的结构来执行 GET 和 POST。与 Android SDK 捆绑在一起的 Apache Commons 库与标准库有显着不同吗?

I'm dipping my toes into Android development. I have a project that will interface with a RESTful resource and I'm trying to figure out how to do a basic GET with params over HTTP. From everything I've read, the consensus seems to be favoring HTTPClient over HttpURLConnection.

I've written a wrapper class with a method that takes care of instantiating the key object to make a request using HTTPClient:

public String get() {  
    String responseString = null;

    HttpClient client = new DefaultHttpClient();
    HttpGet get = new HttpGet();
    try {
        get.setURI(new URI(this.baseURL()));
    } catch (URISyntaxException e1) {
        e1.printStackTrace();
    }

    HttpResponse response;

    try {
        response = client.execute(get);
        responseString = readResponse(response.getEntity());

        if(response != null) {
            System.out.println(responseString);
        }
    } catch(ClientProtocolException e) {
        e.printStackTrace();
    } catch(IOException e) {
        e.printStackTrace();
    }

    return responseString;

}

The line HttpClient client = new DefaultHttpClient(); throws the following exception:

java.lang.RuntimeException: Stub!
at org.apache.http.impl.client.AbstractHttpClient.<init>(AbstractHttpClient.java:5)
at org.apache.http.impl.client.DefaultHttpClient.<init>(DefaultHttpClient.java:7)
at org.rcindustries.appmap.RestClient.get(RestClient.java:54)
at org.rcindustries.appmap.test.functional.RestClientTest.shouldReturnSomeJSon(RestClientTest.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Every example I've seen for HttpClient uses a similar structure to do GETs and POSTs. Is the Apache Commons library bundled with the Android SDK significantly different that the standard lib?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

手长情犹 2024-09-19 17:23:15

对于任何可能感兴趣的人,我遇到了类似的问题 - 尽管我得到的是 DateUtils 的存根错误,而不是 HttpClient

Stephen 似乎是绝对正确的 - Android 平台的类需要模拟器启动并运行: http://simpleprogrammer.com/2010/07/27/the-best-way-to-unit-test-in-android/

非常快上述链接的摘要:

事实上,所有方法都被存根以抛出异常,并显示消息“Stub!”当你打电话给他们时。多可爱啊。

真正的 android.jar 实现存在于模拟器或真实的 Android 设备上。

因此,您可以在模拟器上进行单元测试

  • - 获得完整的 Android 平台、“真正的”android 环境等(但没有常见 Java 单元测试工具的功能 - 例如 JMock)

  • 使用 JVM - 更快,可以使用单元测试助手,如 JMock 等,但是您无法测试任何依赖于 Android 平台的东西。

For anyone who may be interested, I bumped into a similar problem - though instead of HttpClient I was getting stub errors for DateUtils.

Stephen appears to be absolutely correct - classes that are part of the Android platform need the emulator up and running: http://simpleprogrammer.com/2010/07/27/the-best-way-to-unit-test-in-android/

Really quick summary of the above link:

As a matter of fact, all the methods are stubbed out to throw an exception with the message “Stub!” when you call them. How cute.

The real android.jar implementations live on the emulator, or your real Android device.

Therefore, you can unit test...

  • on the emulator - get the full Android platform, "real" android environment etc (but without the power of common Java unit test tools - eg JMock)

OR

  • with the JVM - faster, can use unit test helpers like JMock etc , however you can't test anything that relies on the Android platform.
输什么也不输骨气 2024-09-19 17:23:15

我认为这是 Android 告诉您不能在该平台上运行该单元测试的方式。涉及与 Android 平台(例如本例中的网络)交互的单元测试需要在实际的 Android 设备或功能正常的 Android 模拟器上运行。

(它们无法在常规 Eclipse 上下文中运行。在早期,您需要 Eclipse 的 Android 插件。现在(自 2013 年以来)您应该使用基于 Intellij 构建的 Android Studio。)

显然,您实际上在做的是针对 Android SDK 提供的存根类运行单元测试。这永远行不通。

I think this is Android's way of telling you that you cannot run that unit test on that platform. Unit tests that involve interacting with the Android platform (e.g. the network in this case) need to be run on an actual Android device or a functioning Android emulator.

(They cannot be run in the context of regular Eclipse. In the early days, you needed Android plugins for Eclipse. These days (since 2013) you should be using Android Studio which build on Intellij.)

Apparently, what you were actually doing was running the unit tests against the stub classes provided by the Android SDK. This cannot ever work.

得不到的就毁灭 2024-09-19 17:23:15

在 Android SDK 23 中使用 Proguard 和 com.apache.http.legacy 库时会发生这种情况。

在我将其添加到我的 Proguard 配置中后,它就起作用了:

-keep class org.apache.http.** { *; }
-keep class org.apache.commons.codec.** { *; }
-keep class org.apache.commons.logging.** { *; }
-keep class android.net.compatibility.** { *; }
-keep class android.net.http.** { *; }
-keep class com.android.internal.http.multipart.** { *; }
-dontwarn org.apache.http.**
-dontwarn android.webkit.**

这允许系统 Apache 实现正确覆盖编译的存根进入应用程序。

This happens when using Proguard and the com.apache.http.legacy library in Android SDK 23.

It worked after I added this to my Proguard config:

-keep class org.apache.http.** { *; }
-keep class org.apache.commons.codec.** { *; }
-keep class org.apache.commons.logging.** { *; }
-keep class android.net.compatibility.** { *; }
-keep class android.net.http.** { *; }
-keep class com.android.internal.http.multipart.** { *; }
-dontwarn org.apache.http.**
-dontwarn android.webkit.**

Which allows the system Apache implementation to properly override the stubs compiled into the app.

仅此而已 2024-09-19 17:23:15

在 API 28 之后,旧库(例如 HttpClient)已被弃用,会引发 Stub! 错误,您现在必须将其包含在清单文件中:

  <uses-library
   android:name="org.apache.http.legacy"
   android:required="false" />

https://developers.google.com/maps/documentation/android-sdk/config#specify_requirement_for_apache_http_legacy_library

After API 28, legacy libraries such as HttpClient have been deprecated, throws a Stub! error and you must now include this in your Manifest file:

  <uses-library
   android:name="org.apache.http.legacy"
   android:required="false" />

https://developers.google.com/maps/documentation/android-sdk/config#specify_requirement_for_apache_http_legacy_library

扮仙女 2024-09-19 17:23:15

这个线程有点老了,但是对于不知道的人来说,Robolectric 解决了这个测试问题。

This thread kind of old, but to whoever doesn't know, Robolectric solves this problem for testing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文