基于Jersey开发的一个操作OpenStack的REST服务,利用Jersey的Test Framework编写单元测试类如下:

public class RestAddressTest extends JerseyTest {Integer autoId = 1;@BeforeClasspublic void before() throws Exception {super.setUp();}@AfterClasspublic void after() throws Exception {super.tearDown();}@Overrideprotected Application configure() {return new ResourceConfig(RestAddress.class);}@Test(priority = 0)public void testAdd() {Address ac = new Address();ac.setGateway("1.1.1.1");ac.setName("CLOUD_TEST_BJ");ac.setNicName("ipv4");Response res = target("address").request(MediaType.APPLICATION_JSON).post(Entity.entity(ac, MediaType.APPLICATION_JSON), Response.class);Assert.assertEquals(200, res.getStatus());}@Test(priority = 1)public void testGet() {Response res = target("address").request(MediaType.APPLICATION_JSON).get();List<Address> acl = res.readEntity(new GenericType<List<Address>>() {});this.autoId = acl.get(0).getAutoId();Assert.assertEquals(1, acl.size());}@Test(priority = 2)public void testDelete() {Response response = target("address").path(String.valueOf(autoId)).request(MediaType.APPLICATION_JSON).delete();Assert.assertEquals(200, response.getStatus());}
}

但是在测试时,却始终遇到如下异常:

...
java.lang.IllegalArgumentException: attempt to create delete event with null entityat org.hibernate.event.spi.DeleteEvent.<init>(DeleteEvent.java:31)at org.hibernate.internal.SessionImpl.delete(SessionImpl.java:911)...
[03:39:54,116 ERROR] rollbackTxn - Transaction.rollback
[03:39:54,143 INFO ] Stopped ServerConnector@54089484{HTTP/1.1}{0.0.0.0:9998}
[03:39:54,146 WARN ] /address/1
java.lang.RuntimeException: java.lang.IllegalArgumentException: Status code of the supplied response [500] is not from the required status code family "CLIENT_ERROR".at org.glassfish.jersey.jetty.JettyHttpContainer.handle(JettyHttpContainer.java:197)...
[03:39:54,147 WARN ] Could not send response error 500: java.lang.RuntimeException: java.lang.IllegalArgumentException: Status code of the supplied response [500] is not from the required status code family "CLIENT_ERROR".
Oct 24, 2018 5:39:54 AM org.glassfish.jersey.test.jetty.JettyTestContainerFactory$JettyTestContainer <init>
INFO: Creating JettyTestContainer configured at the base URI http://localhost:9998/
[03:39:54,275 INFO ] jetty-9.2.14.v20151106
[03:39:54,279 INFO ] Started ServerConnector@5042e3d0{HTTP/1.1}{0.0.0.0:9998}
[03:39:54,280 INFO ] Started @5991ms
[03:39:54,312 INFO ] Stopped ServerConnector@5042e3d0{HTTP/1.1}{0.0.0.0:9998}
...
Tests run: 4, Failures: 3, Errors: 0, Skipped: 0, Time elapsed: 4.734 sec <<< FAILURE!Results :Failed tests:   testAdd(com.mycompany.myapp.rest.RestAddressTest): RESTEASY004655: Unable to invoke requesttestGet(com.mycompany.myapp.rest.RestAddressTest): RESTEASY003145: Unable to find a MessageBodyReader of content-type application/json and type interface java.util.ListtestDelete(com.mycompany.myapp.rest.RestAddressTest): expected [500] but found [200]
...

分析异常,可以发现在执行测试用例testDelete()时异常,这里的信息有很强的迷惑性。事实上,在测试用例testDelete()之前执行的testAdd()和testGet()都已经发生了异常,但是却没有输出错误信息。

继续分析发现这应该是个“CLIENT_ERROR”。

在最后的测试结果中,终于暴露了错误的根源。原来,发生错误的是RESTEASY,等等,我们利用Jersey的测试框架进行单元测试,哪里来的RestEasy呢?

检查项目依赖,发现果然同时存在Jersey-ClientRestEasy-Client。突然想到,存在OpenStack的OpenStack4j就是依赖了RestEasy。查看OpenStack4j 3.1.0果然是其引入了RestEasy。

那么RestEasy为什么会在这里被调用呢?感谢StackOverflow,我很快找到了答案。

原来,同样作为JAX-RS的实现,Jersey和RestEasy都扩展了javax.ws.rs.client.ClientBuilder类,并实现了javax.ws.rs.client.Client接口。

其中,Jersey提供的是org.glassfish.jersey.client.JerseyClientBuilder和org.glassfish.jersey.client.JerseyClient,

而RestEasy提供的是org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder和org.jboss.resteasy.client.jaxrs.ResteasyClient。

在同时存在两个JAX-RS实现的时候,由于JAX-RS采用了Java SPI的服务实现注入机制。RestEasy响应了这种机制,声明了ResteasyClientBuilder实现如下:

而Jersey对此机制却无动于衷,实现中根本没有给出JerseyClientBuilder的实现,如下所示:

所以,ResteasyClientBuilder的优先级高于JerseyClientBuilder而被采用。这样,在测试过程中,客户端事实上使用的是RestEasy的ResteasyClient,而非Jersey测试框架期望的JerseyClient。

找到问题的根源,解决起来也很容易了,只要在测试类中重写JerseyTest的getClient()方法,明确指定JerseyClient即可,修改测试类如下:

@Override
public Client getClient() {return JerseyClientBuilder.createClient();
}

参考链接:

https://jersey.github.io/documentation/latest/test-framework.html

https://github.com/jersey/jersey/tree/master/test-framework

https://stackoverflow.com/questions/36348675/unable-to-test-jax-rs-with-json-entity

https://stackoverflow.com/questions/48337023/eclipse-jerseytest-getclient-returns-resteasyclient

https://github.com/ContainX/openstack4j/blob/3.1.0/connectors/resteasy/pom.xml

https://github.com/resteasy/Resteasy/blob/master/resteasy-client/src/main/resources/META-INF/services/javax.ws.rs.client.ClientBuilder

https://github.com/jersey/jersey/tree/master/core-client/src/main

JTF的Unable to invoke request异常或Unable to find a MessageBodyReader of content-type application..异常详解相关推荐

  1. 为什么我的索尼电视显示服务器异常,索尼液晶电视有哪些故障 索尼电视故障代码大全【详解】...

    人人都说索尼大法好,但是索尼大法也有生病的时候,很多家中使用索尼电视的朋友反映,在使用上几年甚至一段时间后,电视机就会出现一些这样那样的故障.不太懂电视.电子设备的朋友可能只会看到表面现象,不知道实际 ...

  2. JSP四大域属性空间(page、request、session、application)详解

    JSP中提供了四个域属性空间:page(页面作用域).request(请求作用域).session会话作用域.application(应用程序作用域). 1.page域: page域作用范围:当前页面 ...

  3. java 非法操作异常_电脑提示非法操作怎么办 电脑系统故障解决方法【详解】

    电脑提示非法操作怎么办? 在电脑操作中,出现"非法操作"提示的几率比蓝屏现象要多出一筹.造成"非法操作"的原因主要出自软件.当一个程序访问其内存地址空间之外的内 ...

  4. 一文详解 Try 和异常的区别

    作者 | 羽生结弦 责编 | 胡雪蕊 出品 | CSDN(ID:CSDNnews) Try 以及异常在C#中是很重要的内容,很多开发人员其实并不是很了解Try 和异常.在这篇文章中我将会各大家具体讲解 ...

  5. Java 里的异常(Exception)详解

    作为一位初学者, 本屌也没有能力对异常谈得很深入.   只不过java里关于Exception的东西实在是很多. 所以这篇文章很长就是了.. 一, 什么是java里的异常 由于java是c\c++ 发 ...

  6. 关于hive异常:Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStor

    关于hive异常:Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStor Exception in t ...

  7. 【异常】Unable to instantiate SparkSession with Hive support because Hive classes a

    [异常]Unable to instantiate SparkSession with Hive support because Hive classes a 参考文章: (1)[异常]Unable ...

  8. 为subclipse配置http代理,解决“RA layer request failed, Unable to connect to a repository at URL ... 错误

    工作环境是通过http代理连接上网的,安装subclipse检出某公共代码仓库时报:RA layer request failed svn: Unable to connect to a reposi ...

  9. QMetaMethod::invoke: Unable to invoke methods with return values in queued connections

    报错信息为: QMetaMethod::invoke: Unable to invoke methods with return values in queued connections 解决方法是: ...

  10. 【QML】C++访问QML函数获取返回值时报:Unable to invoke methods with return values in queued connections

    QMetaMethod::invoke: Unable to invoke methods with return values in queued connections 相关资料可以参考:http ...

最新文章

  1. 奇虎360将于18日在美摘牌 进程早于外界预期
  2. Intel Realsense D435 python 测试是否能将pipeline、config、enable、start单独提出wait for frames循环外?(不能,配置必须全部在外)
  3. flutter 日历_Flutter:一个更贴近真实项目的练习
  4. SpringBoot shedlock MongoDb锁配置
  5. Linux调试分析诊断利器——strace
  6. php mysql 子查询_php – 如何在mySQL的子查询中指定父查询字段?
  7. ireport 3.6.0 增加PDF字体、加粗失效、PDF中文不显示等问题
  8. 微信公众号H5 - 关于微信公众号h5网页实现分享图片
  9. 用matlab画阻尼振动包络线,matlab阻尼振动模拟.doc
  10. 微型计算机的一般结构,微型计算机的基本结构
  11. 【iOS】苹果登录Sign in with Apple
  12. java实现迷宫走法
  13. 检查凭证录入模板的核算项目研发项目是否录入
  14. 大学计算机习题汇总及答案
  15. 领导问“你这块表多少钱?”缺心眼说价钱,不懂这4个话术惹麻烦
  16. BOL简单分析(二)
  17. 【读懂Autosar代码】-6-Function函数的定义
  18. 小酌重构系列[3]——方法、字段的提升和降低
  19. Java中DecimalFormat的用法!
  20. Redis知识点总结归纳

热门文章

  1. 汇编 fsub ,fmul,fdiv,fild,CVTTPS2PI 指令
  2. CSS设置background背景透明
  3. C语言每日一练——第105天:杨辉三角形
  4. ​全球首个机器人抓取云竞赛落幕,华科夺冠,中国团队包揽前三
  5. 计算不可压缩流体 -- 数学基础
  6. 计算机科学与技术保研好不好,2021年北京邮电大学计算机科学与技术专业保研成功上岸经验指导...
  7. 使用metasploit制作钓鱼网站——browser autopwn攻击
  8. HDU 5857 Median (推导)
  9. win10系统显示打印机未连接到服务器,win10系统连接打印机提示“打印处理器不存在”如何解决...
  10. html为标题添加脚注,如何在rmarkdown html中的特定标题下放置脚注?