JaxRs客户端不执行MessageBodyReader

时间:2018-08-16 11:21:00

标签: java java-ee jersey jersey-2.0 java-ee-7

我在设置 MessageBodyReader 时遇到问题-我尝试根据许多教程进行设置,但是从未调用过它的功能。我正在使用 Jersey 2.27

这是我的MessageBodyReader实现:

@Provider
public class MyMsgBodyReader implements MessageBodyReader<Object> {

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

    @Override
    public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
        HashMap<String, String> hash = new HashMap<>();
        hash.put("replaced", "true");
        return hash;
    }

}

我尝试这样称呼它:

@Path("api")
@ApplicationScoped
public class TestClazz {

    @GET
    @Path("test")
    public Response test() {
        Client client = ClientBuilder.newBuilder().register(MyMsgBodyReader.class).build();
        WebTarget target = client.target("http://localhost:3000").path("/api/test");
        Response resp = target.request().get();
        Object receivedEntity = resp.getEntity();
        return Response.ok(receivedEntity).build();
    }
}

虽然receiveEntity应该是带有一个条目的哈希图,但它仍然是我从测试api接收到的原始实体。我什至尝试在MyMsgBodyReader方法中设置断点,并确认甚至没有调用过它们。

我还尝试了多种扫描方式:

@ApplicationPath("v1")
public class App extends Application {

    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> classes = new HashSet<>();
        classes.add(MyMsgBodyReader.class);
        classes.add(
        return classes;
    }

    @Override
    public Set<Object> getSingletons() {
        Set<Object> singletons = new HashSet<>();
        singletons.add(new MsgBodiReader());
        return singletons;
    }
}

我不知道还能尝试什么。

1 个答案:

答案 0 :(得分:2)

您需要决定的第一件事是阅读器将处理哪种类型的数据。您可以使用@Consumes批注进行此操作。您将此放在阅读器类的顶部。根据响应的Content-Type,Jersey将选择与@Consumes中的媒体类型相匹配的正确阅读器。如果有多个匹配的阅读器,则下一步是测试isReadable()方法。如果一项检查通过,则Jersey将检查优先级。您可以在阅读器上添加@Priority(int)批注。或者,您可以将优先级作为第二个参数传递给register()方法。较高的优先级将具有最高优先级。如果您正在@Consumes中使用已经有标准阅读器的媒体类型,则可能要使用@Priority以便使用您的媒体类型。

如果仍然没有呼叫阅读器,则应检查响应的Content-Type并确保它是您所期望的。您还可以设置Accept头(可以通过将媒体类型传递给request()方法来隐式设置。

这是一个叫读者 的例子。

@Provider
@Conumes("application/custom")
public class MyReader implements MessageBodyReader<String> {
}

Response res = client.target("test")
        .register(MyReader.class)
        .request("application/custom")
        .get();

假定服务器确实返回类型为application/custom的数据,则应调用此读取器。如果服务器不能够返回数据格式,而您请求该类型,则应该得到一个406 Not Acceptable错误。

此外,您不应使用Response#getEntity()获取返回的数据。您应该使用readEntity(Class),并传入您想要将数据转换为的Java类型(使用MessageBodyReader)。对于泛型,您应该使用GenericType

Map<String, String> data = res.readEntity(new GenericType<Map<String, String>>(){});

这是使用Jersey Test Framework的完整测试。

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.MessageBodyReader;

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class CustomReaderTest extends JerseyTest {

    private static final String DATA = "UselessStaticData";
    private static final String CUSTOM_MEDIA_TYPE = "application/useless";

    @Consumes(CUSTOM_MEDIA_TYPE)
    public static class UselessReader implements MessageBodyReader<String> {

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

        @Override
        public String readFrom(Class<String> aClass, Type type, Annotation[] annotations,
                               MediaType mediaType, MultivaluedMap<String,String> multivaluedMap,
                               InputStream inputStream) throws IOException, WebApplicationException {
            return DATA;
        }
    }


    @Path("test")
    public static class TestResource {

        @GET
        @Produces(CUSTOM_MEDIA_TYPE)
        public InputStream post(String data) {
            return new ByteArrayInputStream("Test".getBytes(StandardCharsets.UTF_8));
        }
    }

    @Override
    public ResourceConfig configure() {
        return new ResourceConfig()
                .register(TestResource.class);
    }

    @Test
    public void testIt() {
        Response res = target("test")
                .register(UselessReader.class)
                .request(CUSTOM_MEDIA_TYPE)
                .get();

        assertThat(res.readEntity(String.class)).isEqualTo(DATA);
    }
}