代码之家  ›  专栏  ›  技术社区  ›  Vasiliy

使用GSON时,在JerseyTest中引发MessageBodyProviderNotFoundException

  •  1
  • Vasiliy  · 技术社区  · 9 年前

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

    JerseyTest 子类:自定义 GsonProvider 除非为每个调用显式注册,否则无法识别。然而,如果我将应用程序部署到Tomcat,则会被识别。

    ResourceConfig :

    @ApplicationPath("")
    public class MyResourceConfig extends ResourceConfig {
    
        public MyResourceConfig() {
            register(GsonProvider.class);
    
            register(SomeResource.class);
        }
    }
    

    实施 GSON提供商

    @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));
        }
    }
    

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

    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 有利于部署,但 每个请求需要额外注册。

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

    1 回复  |  直到 9 年前
        1
  •  1
  •   Paul Samsotha    9 年前

    您还没有显示stacktrace,但我很确定,如果您仔细观察它,就会发现它实际上是一个客户端错误。您需要做的是向客户端注册gson提供程序,因为您正试图将响应JSON反序列化为POJO

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

    这个 configureClient JerseyTest 您可以覆盖。