【问题标题】:MessageBodyProviderNotFoundException is thrown in JerseyTest when using GSON使用 GSON 时在 JerseyTest 中抛出 MessageBodyProviderNotFoundException
【发布时间】:2017-06-27 11:25:12
【问题描述】:

我使用 Jersey 并决定使用 GSON 而不是 Moxy 来处理 JSON(不喜欢 Moxy 需要 setter 的事实)。

到目前为止一切正常,除了我的JerseyTest 子类中的一个非常烦人的问题:除非为每个调用明​​确注册,否则无法识别自定义GsonProvider。但是,如果我将应用程序部署到 Tomcat,它就会被识别出来。

我的ResourceConfig

@ApplicationPath("")
public class MyResourceConfig extends ResourceConfig {

    public MyResourceConfig() {
        register(GsonProvider.class);

        register(SomeResource.class);
    }
}

GsonProvider 的实现(尽管我认为这与我遇到的问题无关):

@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class GsonProvider<T> implements MessageBodyReader<T>, MessageBodyWriter<T> {

    private final Gson mGson;

    public GsonProvider() {
        mGson = new GsonBuilder().create();
    }

    @Override
    public boolean isReadable(Class<?> type, Type genericType,
                              Annotation[] annotations, MediaType mediaType) {
        return true;
    }

    @Override
    public T readFrom(Class<T> type, Type genericType, Annotation[] annotations,
                      MediaType mediaType, MultivaluedMap<String, String> httpHeaders,
                      InputStream entityStream) throws IOException, WebApplicationException {

        InputStreamReader reader = new InputStreamReader(entityStream, "UTF-8");
        try {
            return mGson.fromJson(reader, type);
        } finally {
            reader.close();
        }
    }

    @Override
    public boolean isWriteable(Class<?> type, Type genericType,
                               Annotation[] annotations, MediaType mediaType) {
        return true;
    }

    @Override
    public long getSize(T t, Class<?> type, Type genericType,
                        Annotation[] annotations, MediaType mediaType) {
        return -1;
    }

    @Override
    public void writeTo(T t, Class<?> type, Type genericType, Annotation[] annotations,
                        MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
                        OutputStream entityStream) throws IOException, WebApplicationException {

        PrintWriter printWriter = new PrintWriter(entityStream);
        try {
            String json = mGson.toJson(t);
            printWriter.write(json);
            printWriter.flush();
        } finally {
            printWriter.close();
        }
    }
}

此测试结果为MessageBodyProviderNotFoundException

public class SomeResourceTest extends JerseyTest {
    @Override
    public Application configure() {
        return new MyResourceConfig();
    }

    @Test
    public void someApi_200Returned() throws Exception {
        // Arrange
        // Act
        SomeResponse response =
                target("/somepath")
                        .request()
                        .post(Entity.json(""), SomeResponse.class);
        // Assert
        assertThat(response.getStatus(), is(200));
    }
}

为了解决这个问题,我注册了GsonProvider 请求。以下更改使测试通过:

public class SomeResourceTest extends JerseyTest {
    @Override
    public Application configure() {
        return new MyResourceConfig();
    }

    @Test
    public void someApi_200Returned() throws Exception {
        // Arrange
        // Act
        SomeResponse response =
                target("/somepath")
                        .register(GsonProvider.class)
                        .request()
                        .post(Entity.json(""), SomeResponse.class);
        // Assert
        assertThat(response.getStatus(), is(200));
    }
}

因此,在MyResourceConfig 中注册GsonProvider 有利于部署,但JerseyTest 需要针对每个请求进行额外注册。

虽然我可以忍受,但这很烦人,很耗时,而且很难与其他团队成员交流。这个问题有什么解决办法吗?

【问题讨论】:

    标签: java gson jersey-2.0 jersey-test-framework


    【解决方案1】:

    您还没有显示堆栈跟踪,但我很确定如果您仔细查看它,它会显示它实际上是客户端错误。您需要做的是向客户端注册 gson 提供程序,因为您正在尝试将响应 JSON 反序列化为 POJO

    @Override
    public void configureClient(ClientConfig config) {
        config.register(GsonProvider.class)
    }
    

    configureClient 方法是JerseyTest 中可以覆盖的方法。

    【讨论】:

    • 是的!我没有意识到客户端是一个独立的实体。谢谢
    • 我必须在任何呼叫中注册提供程序,它确实有效。但是,我很确定有一种通用的方法可以解决这个问题,而您的答案正是我所需要的。把这个逻辑放到MyJerseyTest基类中,生活又美好了:)
    猜你喜欢
    • 2017-07-18
    • 1970-01-01
    • 2014-11-12
    • 1970-01-01
    • 2012-07-14
    • 1970-01-01
    • 2020-07-28
    • 1970-01-01
    相关资源
    最近更新 更多