Android 上的 Jersey 客户端 - NullPointerException
我正在尝试为我构建的 Web 服务创建一个简单的 Android 客户端,但在运行时出现问题。
这是客户端:
public class MyClient extends AsyncTask<EditText, Integer, String> {
private EditText text;
protected String doInBackground(EditText... strings) {
RuntimeDelegate
.setInstance(new com.sun.ws.rs.ext.RuntimeDelegateImpl());
WebResource wbr;
Client client = Client.create();
wbr = client
.resource("http://my.ip:8080/MazeService/rest/service/hello");
String result = wbr.queryParam("number", "10")
.accept(MediaType.APPLICATION_JSON).get(String.class);
text = strings[0];
return result;
}
protected void onProgressUpdate(Integer... progress) {
// setProgressPercent(progress[0]);
}
protected void onPostExecute(String result) {
if (result != null)
this.text.setText(result);
else
Log.d("MyApp", "No Result");
}
}
和服务:
@Path("/service")
public class AndroidService {
@GET
@Produces(MediaType.APPLICATION_JSON )
@Path("/hello")
public String getJSON(@QueryParam("number") String nr)
{
String s = "Hi there! The number is: "+nr;
return s;
}
}
我在 LogCat 中得到这个堆栈跟踪:
02-18 16:26:06.446: E/AndroidRuntime(1381): FATAL EXCEPTION: AsyncTask #1
02-18 16:26:06.446: E/AndroidRuntime(1381): java.lang.RuntimeException: An error occured while executing doInBackground()
02-18 16:26:06.446: E/AndroidRuntime(1381): at android.os.AsyncTask$3.done(AsyncTask.java:278)
02-18 16:26:06.446: E/AndroidRuntime(1381): at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
02-18 16:26:06.446: E/AndroidRuntime(1381): at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
02-18 16:26:06.446: E/AndroidRuntime(1381): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
02-18 16:26:06.446: E/AndroidRuntime(1381): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
02-18 16:26:06.446: E/AndroidRuntime(1381): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
02-18 16:26:06.446: E/AndroidRuntime(1381): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
02-18 16:26:06.446: E/AndroidRuntime(1381): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
02-18 16:26:06.446: E/AndroidRuntime(1381): at java.lang.Thread.run(Thread.java:856)
02-18 16:26:06.446: E/AndroidRuntime(1381): Caused by: java.lang.NullPointerException
02-18 16:26:06.446: E/AndroidRuntime(1381): at javax.ws.rs.core.MediaType.valueOf(MediaType.java:119)
02-18 16:26:06.446: E/AndroidRuntime(1381): at com.sun.jersey.api.client.ClientResponse.getType(ClientResponse.java:615)
02-18 16:26:06.446: E/AndroidRuntime(1381): at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:532)
02-18 16:26:06.446: E/AndroidRuntime(1381): at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:506)
02-18 16:26:06.446: E/AndroidRuntime(1381): at com.sun.jersey.api.client.WebResource.handle(WebResource.java:674)
02-18 16:26:06.446: E/AndroidRuntime(1381): at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
02-18 16:26:06.446: E/AndroidRuntime(1381): at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:503)
02-18 16:26:06.446: E/AndroidRuntime(1381): at com.maze.client.MyClient.doInBackground(MyClient.java:25)
02-18 16:26:06.446: E/AndroidRuntime(1381): at com.maze.client.MyClient.doInBackground(MyClient.java:1)
02-18 16:26:06.446: E/AndroidRuntime(1381): at android.os.AsyncTask$2.call(AsyncTask.java:264)
02-18 16:26:06.446: E/AndroidRuntime(1381): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
02-18 16:26:06.446: E/AndroidRuntime(1381): ... 5 more
我不明白问题是什么,因为类似的客户端在 PC 上工作。 IP 地址没有问题,因为我可以从 Android VirtualDevice 访问服务器。
Android 版本是 4.0.3 API 版本 15。对于客户端,我使用 Jersey 1.11。
编辑
我还尝试使用 EditText 删除整个内容,因为有人告诉我它没有按应有的方式使用。尽管如此,我还是遇到了同样的错误。我根本不明白我做错了什么。如果我需要显示任何其他附加信息,请告诉我。另外,任何想法都是好的。我是 Android 新手,可能犯过一些愚蠢的错误。
I am trying to create a simple Android client for a web service I have built, but something goes wrong at runtime.
Here is the Client:
public class MyClient extends AsyncTask<EditText, Integer, String> {
private EditText text;
protected String doInBackground(EditText... strings) {
RuntimeDelegate
.setInstance(new com.sun.ws.rs.ext.RuntimeDelegateImpl());
WebResource wbr;
Client client = Client.create();
wbr = client
.resource("http://my.ip:8080/MazeService/rest/service/hello");
String result = wbr.queryParam("number", "10")
.accept(MediaType.APPLICATION_JSON).get(String.class);
text = strings[0];
return result;
}
protected void onProgressUpdate(Integer... progress) {
// setProgressPercent(progress[0]);
}
protected void onPostExecute(String result) {
if (result != null)
this.text.setText(result);
else
Log.d("MyApp", "No Result");
}
}
and the Service:
@Path("/service")
public class AndroidService {
@GET
@Produces(MediaType.APPLICATION_JSON )
@Path("/hello")
public String getJSON(@QueryParam("number") String nr)
{
String s = "Hi there! The number is: "+nr;
return s;
}
}
I get this stacktrace in LogCat:
02-18 16:26:06.446: E/AndroidRuntime(1381): FATAL EXCEPTION: AsyncTask #1
02-18 16:26:06.446: E/AndroidRuntime(1381): java.lang.RuntimeException: An error occured while executing doInBackground()
02-18 16:26:06.446: E/AndroidRuntime(1381): at android.os.AsyncTask$3.done(AsyncTask.java:278)
02-18 16:26:06.446: E/AndroidRuntime(1381): at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
02-18 16:26:06.446: E/AndroidRuntime(1381): at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
02-18 16:26:06.446: E/AndroidRuntime(1381): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
02-18 16:26:06.446: E/AndroidRuntime(1381): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
02-18 16:26:06.446: E/AndroidRuntime(1381): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
02-18 16:26:06.446: E/AndroidRuntime(1381): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
02-18 16:26:06.446: E/AndroidRuntime(1381): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
02-18 16:26:06.446: E/AndroidRuntime(1381): at java.lang.Thread.run(Thread.java:856)
02-18 16:26:06.446: E/AndroidRuntime(1381): Caused by: java.lang.NullPointerException
02-18 16:26:06.446: E/AndroidRuntime(1381): at javax.ws.rs.core.MediaType.valueOf(MediaType.java:119)
02-18 16:26:06.446: E/AndroidRuntime(1381): at com.sun.jersey.api.client.ClientResponse.getType(ClientResponse.java:615)
02-18 16:26:06.446: E/AndroidRuntime(1381): at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:532)
02-18 16:26:06.446: E/AndroidRuntime(1381): at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:506)
02-18 16:26:06.446: E/AndroidRuntime(1381): at com.sun.jersey.api.client.WebResource.handle(WebResource.java:674)
02-18 16:26:06.446: E/AndroidRuntime(1381): at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
02-18 16:26:06.446: E/AndroidRuntime(1381): at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:503)
02-18 16:26:06.446: E/AndroidRuntime(1381): at com.maze.client.MyClient.doInBackground(MyClient.java:25)
02-18 16:26:06.446: E/AndroidRuntime(1381): at com.maze.client.MyClient.doInBackground(MyClient.java:1)
02-18 16:26:06.446: E/AndroidRuntime(1381): at android.os.AsyncTask$2.call(AsyncTask.java:264)
02-18 16:26:06.446: E/AndroidRuntime(1381): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
02-18 16:26:06.446: E/AndroidRuntime(1381): ... 5 more
I do not understand what the problem is, since a similar client works on PC. There is no problem with the IP address, since I can access the server from the Android VirtualDevice.
The Android version is 4.0.3 API version 15. For the client I used Jersey 1.11.
EDIT
I have also tried to remove the whole thing with the EditText, since someone told me it isn't used as it should be. Still, I got the same error. I simply can not understand what am I doing wrong. If I should display any other additional information, please let me know. Also, ANY idea is good. I am new to Android and I might have made some stupid mistakes.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
保罗的建议是正确的。我对这个主题有了更深入的了解,并找到了原因。
Android apk 打包工具(sdklib.jar 中的 APKBuilder 类)在创建包时会忽略不同的文件夹 (来源)。这些文件夹之一是 META-INF - 无论它是在附加库中还是在项目的源文件夹中。
Jersey 版本 1.8(也可能是其他版本,但我没有测试它)的解决方法是为 ServiceFinder$ServiceIteratorProvider 具有硬编码的提供程序类名。我的实现基于 this Lucas 提出的实现:
我删除了大部分类,因为我没有使用它们,而且它们还在 dalvik vm 上导致验证错误...
注意:这意味着通过此实现,您只能使用 Jersey 支持的标头/类型的子集(我只需要字符串)。要支持其他类型,您必须添加位于 jersey-client.jar 的 META-INF/services 文件夹(或来自 Lucas 的实现)中的提供程序,并检查它们是否不会在 Android 上导致验证错误。
上面的代码应按如下方式使用:
编辑:
问题似乎是已在 android-maven-plugin 中修复。
[电子邮件受保护] 写道:
Paul's suggestion is correct. I got a little bit deeper in that subject and found a reason.
Android apk packaging tool (APKBuilder class from sdklib.jar) ignores different folders while it creates the package (source). One of those folders is META-INF - no matter if its in the attached library or in the project's source folder.
Workaround for version 1.8 (and probably other also, but I didn't test it) of Jersey is to provide custom (default one looks up META-INF/services/ which is not present in android apk) implementation for ServiceFinder$ServiceIteratorProvider which has hard coded provider class names. I based my implementation on this implementation proposed by Lucas:
I removed most of the classes since I didn't use them and also they were causing verification errors on dalvik vm...
NOTE: It means that with this implementation you can use only subset of headers/types supported by Jersey (I needed only String). To support other types you have to add providers located in META-INF/services folder of jersey-client.jar (or from Lucas' implementation) and check if they don't cause verification errors on Android.
The above code should be used as follows:
EDIT:
It seems that the problem have been fixed in android-maven-plugin.
[email protected] wrote:
遵循代码:
com/sun/jersey/api/client/ClientResponse.getType()
我会检查 MediaType 使用的委托不为
null
。javax/ws/rs/core/MediaType.valueOf(java.lang.String)
看起来像对于一个客户端 (Android),
delegate
可能为null
,而对于另一客户端则不是null
。看一下这个以了解委托是如何初始化的。它可能对您的调查有所帮助。
javax/ws/rs/ext/RuntimeDelegate.java
Following the code:
com/sun/jersey/api/client/ClientResponse.getType()
I'd check that the delegate used by MediaType is not
null
.javax/ws/rs/core/MediaType.valueOf(java.lang.String)
It looks like maybe
delegate
isnull
for one client (Android) and notnull
for your other client.Take a look at this to get an idea for how the delegate is initialised. It may help your investigations.
javax/ws/rs/ext/RuntimeDelegate.java