博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JTF的Unable to invoke request异常或Unable to find a MessageBodyReader of content-type application..异常详解
阅读量:4178 次
发布时间:2019-05-26

本文共 4275 字,大约阅读时间需要 14 分钟。

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

public class RestAddressTest extends JerseyTest {    Integer autoId = 1;    @BeforeClass    public void before() throws Exception {        super.setUp();    }    @AfterClass    public void after() throws Exception {        super.tearDown();    }    @Override    protected 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
acl = res.readEntity(new GenericType
>() {}); 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 entity	at org.hibernate.event.spi.DeleteEvent.
(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/1java.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
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 request testGet(com.mycompany.myapp.rest.RestAddressTest): RESTEASY003145: Unable to find a MessageBodyReader of content-type application/json and type interface java.util.List testDelete(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即可,修改测试类如下:

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

 

参考链接:

 

转载地址:http://dqlai.baihongyu.com/

你可能感兴趣的文章
SpringBoot | 以maven的方式启动项目
查看>>
SpringBoot | 如何配置静态资源的地址与访问路径
查看>>
SpringBoot | 加入shiro之后如何优雅的访问默认目录static下的静态资源
查看>>
DateTimeFormatter时间工具类
查看>>
SpringBoot | 实现切面
查看>>
调用bat文件工具类
查看>>
SpringBoot | 配置fastjson
查看>>
IDEA RESTful Client JSON数据请求
查看>>
DateUtil时间工具类
查看>>
OkHttp3Util工具类
查看>>
获取完整的请求URL
查看>>
Maven常用命令
查看>>
SpringBoot | 运行报错,无法加载oracle连接驱动
查看>>
为什么阿里巴巴禁止在 foreach 循环里进行元素的 remove/add 操作
查看>>
AWS EC2如何从普通用户切换为root用户
查看>>
aws设置root用户通过密码进行登陆
查看>>
click方法不生效的
查看>>
mysql排行榜并列与不并列
查看>>
SpringBoot | Mybatis申明为Mapper文件
查看>>
JPA主键生成策略
查看>>