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?
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...
OR
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With