为什么Resteasy-mobile中的ClientResponseFailure会导致StackOverflowError?解决方法?

时间:2012-10-26 08:15:09

标签: java android resteasy

我目前正在开发一款Android应用程序,它使用Resteasy-mobile进行REST(JAXRS)实现,而Jackson用于与JSON进行序列化。后者由Resteasy在后台完成。

Serverside我有一个Jersey webservice,也使用jackson进行JSON序列化。

Resteasy客户端和webresource都实现了一个JAXRS注释界面:

    @Path("/equipment")
    @Consumes({"application/json"})
    @Produces({"application/json"})
    public interface AndroidEquipmentResourceIF
    {
      @GET 
      public Model getModel();

      @GET 
      @Path("/version") 
      public String getVersion();

      @GET 
      @Path("/{eId}") 
      public List<Equipment> getEquipmentListWithId(@PathParam("eId") String eId);
    }

Clientside,此接口被加载到工厂,并返回一个带有此接口的对象,该接口在调用方法时处理HTTP / URL /序列化过程。

当调用具有无效ID的Equipment实体时,如果找不到该实体,服务器将抛出WebApplicationException。客户端,这可能导致该方法返回null。

如果我想对状态代码执行某些操作,例如404 - Not found401 - Unauthorized,我可能需要响应对象吗?我认为Resteasy和Jersey在后台使用Response对象,那么有没有办法使用Resteasy访问Response对象或状态代码?

EDIT1:忘了提到第二个选项。我注意到可以将对象包装在响应对象中。因此,如果我将所有特定的域对象返回类型替换为Response,并以某种方式将对象包装在响应中,我可以从Response对象中提取对象吗?这对我来说听起来不太干净,只是为了能够看到状态代码。另外,我想尽可能远离手动解析JSON。

EDIT2:发现可以拦截WebApplicationException,Resteasy客户端抛出ClientResponseFailure异常,可以在拦截器中捕获。问题是,永远不会抛出异常?它似乎陷入某个无限循环中。

我收到以下异常:

10-26 10:52:10.048: E/AndroidRuntime(282): Caused by: java.lang.StackOverflowError
10-26 10:52:10.048: E/AndroidRuntime(282):  at java.util.regex.Matcher.reset(Matcher.java:151)
10-26 10:52:10.048: E/AndroidRuntime(282):  at java.util.regex.Matcher.reset(Matcher.java:211)
10-26 10:52:10.048: E/AndroidRuntime(282):  at java.util.regex.Matcher.<init>(Matcher.java:127)
10-26 10:52:10.048: E/AndroidRuntime(282):  at java.util.regex.Pattern.split(Pattern.java:405)
10-26 10:52:10.048: E/AndroidRuntime(282):  at java.util.regex.Pattern.split(Pattern.java:355)
10-26 10:52:10.048: E/AndroidRuntime(282):  at java.lang.String.split(String.java:2125)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.plugins.delegates.MediaTypeHeaderDelegate.parse(MediaTypeHeaderDelegate.java:33)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.plugins.delegates.MediaTypeHeaderDelegate.fromString(MediaTypeHeaderDelegate.java:18)
10-26 10:52:10.048: E/AndroidRuntime(282):  at javax.ws.rs.core.MediaType.valueOf(MediaType.java:173)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.core.BaseClientResponse.getMediaType(BaseClientResponse.java:362)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.core.BaseClientResponse.getEntity(BaseClientResponse.java:346)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.core.BaseClientResponse.getEntity(BaseClientResponse.java:319)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.core.BaseClientResponse.getEntity(BaseClientResponse.java:442)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.core.BaseClientResponse.copyFromError(BaseClientResponse.java:94)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.ClientResponseFailure.<init>(ClientResponseFailure.java:32)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.core.BaseClientResponse.createResponseFailure(BaseClientResponse.java:488)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.core.BaseClientResponse.createResponseFailure(BaseClientResponse.java:479)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.core.BaseClientResponse.readFrom(BaseClientResponse.java:384)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.core.BaseClientResponse.getEntity(BaseClientResponse.java:346)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.core.BaseClientResponse.getEntity(BaseClientResponse.java:319)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.core.BaseClientResponse.getEntity(BaseClientResponse.java:442)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.core.BaseClientResponse.copyFromError(BaseClientResponse.java:94)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.ClientResponseFailure.<init>(ClientResponseFailure.java:32)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.core.BaseClientResponse.createResponseFailure(BaseClientResponse.java:488)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.core.BaseClientResponse.createResponseFailure(BaseClientResponse.java:479)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.core.BaseClientResponse.readFrom(BaseClientResponse.java:384)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.core.BaseClientResponse.getEntity(BaseClientResponse.java:346)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.core.BaseClientResponse.getEntity(BaseClientResponse.java:319)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.core.BaseClientResponse.getEntity(BaseClientResponse.java:442)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.core.BaseClientResponse.copyFromError(BaseClientResponse.java:94)
10-26 10:52:10.048: E/AndroidRuntime(282):  at org.jboss.resteasy.client.ClientResponseFailure.<init>(ClientResponseFailure.java:32)

1 个答案:

答案 0 :(得分:2)

按照以下方式运行:

Resteasy-mobile是JBOSS Resteasy 2.2.1 GA的修剪版本。已删除许多内容以使其在Android上运行。但是有点太多了。

我发现如果抛出ClientResponseFailure,则将其实体的响应转换为Byte数组,并将再次读取以复制到ClientResponseFailure。问题是,修剪后的版本只包含用于字符串和text / plain的Messagebody读取器/写入器,而不包含字节数组。因此,在尝试阅读实体时,它会尝试抛出新的ClientResponseFailure,因为无法找到与MessageBodyReader兼容的Byte[]。然后它再次将此实体强制转换为字节数组,尝试再次读取它,从而进入一个以StackOverflowError结尾的无限循环。

通过将未修剪版本的Resteasy中缺少的ByteArrayProviderReadFromStream类添加到类路径(org.jboss.resteasy.plugins.providers.ByteArrayProviderorg.jboss.resteasy.util.ReadFromStream),ClientErrorInterceptorlink)就像一个魅力!

编辑:我说得太早了,还没有像魅力那样工作。 ResteasyProviderFactory也已经过修改,可以在Android中运行。 .getInstance()方法不断返回一个新实例,所以如果你注册一个ClientErrorInterceptor:ResteasyProviderFactory.getInstance().addClientErrorInterceptor(new DataExceptionInterceptor());它不起作用。 ProxyFactory将使用ResteasyProviderFactory的新实例。

要解决此问题,用于添加拦截器的ResteasyProviderFactory应传递给ProxyFactory.create()

像这样:

ResteasyProviderFactory pf;
BasicHttpParams params;

pf = ResteasyProviderFactory.getInstance();

pf.addClientErrorInterceptor(new DataExceptionInterceptor());

params = new BasicHttpParams();
HttpProtocolParams.setVersion(params,
                              HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params,
                                     HTTP.DEFAULT_CONTENT_CHARSET);
HttpProtocolParams.setUseExpectContinue(params,
                                        false);
return ProxyFactory.create(AndroidEquipmentResourceIF.class,
                           ProxyFactory.createUri(requestURI),
                           new ThreadSafeApacheHttpClient4Executor(params),
                           pf);