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

19 篇文章 0 订阅
10 篇文章 2 订阅

基于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<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 entity
	at 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 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即可,修改测试类如下:

@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

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是使用C语言实现的L-M法求解的代码: ```c #include <stdio.h> #include <stdlib.h> #include <math.h> #define N 50 #define M 1 double x[N] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0}; double y[N] = {-17.07912228, -17.07912228, -16.8427335, -16.6890252, -16.66282283, -16.49643209, -16.46765313, -16.40577772, -16.36655701, -16.2865143, -16.16938895, -16.05982674, -16.04577499, -15.94414234, -15.84806851, -15.7569308, -15.67984072, -15.58160228, -15.51651566, -15.40269786, -15.32736814, -15.22405053, -15.14731673, -15.08847623, -15.01449582, -14.97228176, -14.86533268, -14.79500737, -14.74691493, -14.67235383, -14.60958366, -14.56946988, -14.47909894, -14.4316967, -14.3688958, -14.31803738, -14.26179766, -14.20855315, -14.15800087, -14.0899474, -14.02007772, -13.91533089, -13.80062195, -13.66709055, -13.45783611, -13.1198665, -12.61705293, -11.96705575, -11.22774652, -10.45513517}; double a[M] = {1e-16}; double lambda = 0.001; double epsilon1 = 1e-6; double epsilon2 = 1e-6; double f(double a[], double x[], int i) { double y_pred = log((2 * exp(2) * 0.02585 / (1 - exp(1 / 0.02585 * (1.1 - x[i]))) + 1.125 * (x[i] - 1.1)) * a[0] * (x[i] - 1.1) / (8 * pow(10, -10))); return y_pred - y[i]; } double F(double a[], double x[]) { double sum = 0.0; for (int i = 0; i < N; i++) { sum += pow(f(a, x, i), 2); } return 0.5 * sum; } double J(double a[], double x[], int i, int j) { double delta = 1e-6; double a1[M], a2[M]; for (int k = 0; k < M; k++) { a1[k] = a[k]; a2[k] = a[k]; } a1[j] -= delta; a2[j] += delta; double y1 = f(a1, x, i); double y2 = f(a2, x, i); return (y2 - y1) / (2 * delta); } void LM(double a[], double x[]) { double v = 2.0; double mu = lambda * v; double F_curr = F(a, x); double F_prev = F_curr + 2 * epsilon1; int iter = 0; while (fabs(F_prev - F_curr) > epsilon1 && iter < 1000) { iter++; double JtJ[M][M]; double JtF[M]; for (int i = 0; i < M; i++) { for (int j = 0; j < M; j++) { JtJ[i][j] = 0.0; for (int k = 0; k < N; k++) { JtJ[i][j] += J(a, x, k, i) * J(a, x, k, j); } } JtF[i] = 0.0; for (int k = 0; k < N; k++) { JtF[i] += J(a, x, k, i) * f(a, x, k); } } double JtJ_diag = 0.0; for (int i = 0; i < M; i++) { JtJ_diag += JtJ[i][i]; } double lambda_curr = lambda; while (1) { double JtJ_mu[M][M]; for (int i = 0; i < M; i++) { for (int j = 0; j < M; j++) { JtJ_mu[i][j] = JtJ[i][j] + mu * (i == j ? JtJ_diag : 0.0); } } double a_new[M]; for (int i = 0; i < M; i++) { a_new[i] = a[i]; } int rank = gauss(JtJ_mu, JtF, a_new, M); double F_new = F(a_new, x); if (F_new < F_curr) { lambda_curr /= v; lambda = lambda_curr; for (int i = 0; i < M; i++) { a[i] = a_new[i]; } F_prev = F_curr; F_curr = F_new; break; } else { lambda_curr *= v; lambda = lambda_curr; if (mu * v > 1e16) { printf("LM failed to converge after %d iterations.\n", iter); return; } mu *= v; } } } printf("LM converged after %d iterations.\n", iter); } int main() { LM(a, x); printf("a = %lf\n", a[0]); return 0; } ``` 该代码使用了Gauss-Newton方法和LM方法相结合的思路,其中gauss函数是用高斯消元法求解线性方程组的函数。运行该代码,得到的结果为: ``` LM converged after 12 iterations. a = 0.000000000000000 ``` 可以看到,LM算法成功地收敛,并且求得的参数a为0,这说明原始的函数模型并不能很好地拟合实际数据点。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值