MessageBody Writer / Reader

时间:2014-11-18 01:41:50

标签: java rest jersey jax-rs gson

我正在尝试让Jersey支持 GSON ,为此我已经读过我需要实现自定义 MessageBodyWriter MessageBodyReader

现在我的问题是我找不到这两个接口的任何明确定义。

来自doc:

public interface MessageBodyWriter<T>
  

支持将Java类型转换为的提供程序的合同   一条小溪。要添加MessageBodyWriter实现,请注释   使用@Provider实现类。 MessageBodyWriter   可以使用Produces注释实现来限制媒体   它被认为适合的类型。

public interface MessageBodyReader<T>
  

支持将流转换为的提供商的合同   Java类型。 MessageBodyReader实现可以使用注释   消费以限制将被考虑的媒体类型   适当。必须是实现MessageBodyReader合同的提供者   要么以编程方式在JAX-RS运行时注册,要么必须注册   使用@Provider注释进行注释,以便自动发现   提供商扫描阶段的JAX-RS运行时。

任何人都能解释一下具体意味着什么吗?

为什么我需要在GSON支持的情况下实现它们呢?

谢谢。

1 个答案:

答案 0 :(得分:1)

提供商的合同......

只是表示接口的公开方法集。如果我们实现接口,我们必须实现一组契约方法,框架将使用它们来实现我们的实现

MessageBodyWriter - 支持将Java类型转换为流的提供商的合同 - 从我们的JAX-RS资源方法中,我们返回Response实体主体(Java对象)或Java对象。消息正文编写器负责将此Java对象转换为响应的输出流。例如(仅仅是为了游戏想象我们还没有支持JAXB编组)

@Override
public void writeTo(Customer c, Class<Customer> type, 
                    Type genericType, Annotation[] annotations, 
                    MediaType mediaType, 
                    MultivaluedMap<String,Object> httpHeaders, 
                    OutputStream entityStream) {

    JAXBContext context = JAXBContext.newInstance(type);
    Marshaller marsaller = context.createMarshaller();
    marshaller.marshal(c, entityStream);
}

您可以看到我创建了Marshaller,它将Customer对象封送到提供的(框架)OutputStream

MessageBodyReader - 支持将流转换为Java类型的提供程序的合同 - 与编写器相同的交易,但这次是相反的过程。在将Java类型传递给JAX-RS资源方法之前,需要对其进行转换。例如

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

    JAXBContext context = JAXBContext.newInstance(Customer.class);
    Unmarshaller unmarshaller = context.createUnmarshaller();

    return (Customer)unarshaller.unmarshal(entityStream);
}

MessageBodyWriter ...

  

要添加MessageBodyWriter实现,请使用@Provider注释实现类。可以使用MessageBodyWriterProduces实施进行注释,以限制适合其的媒体类型

JAX-RS具有 Providers 的概念。你可以想到 Component 的另一个词。当我们使用@Provider注释我们的JAX-RS实现的类时,它变得可以成为组件,由框架管理。

使用MessageBodyWriters/MessageBodyReaders,有一种特定的算法可用于确定每个请求/响应将使用哪个编写器/阅读器。基本上发生的是JAX-RS根据@Produces注释匹配计算一个或多个列表。例如,如果我们的资源方法或资源类使用@Produces(MediaType.APPLICATION_XML)进行注释,并且我们的提供者(编写者)也使用此注释,那么我们的编写器将被放入此列表中。然后这些提供者按一些算法排序。最后,在每个编写器上调用isWritable方法,直到其中一个返回true。那是将要使用的作家。例如

@Provider
@Produces(MediaType.APPLICATION_XML)
public class MyJAXBMessageBodyWriter 
                  implements MessaheBodyWriter<Customer> {
    @Override
    public boolean isWriteable(Class<Customer> type, Type genericType, 
                Annotation[] annotations, MediaType mediaType) {

        return type == Customer.class;
    }
}

@GET
@Produces(MediaType.APPLICATION_XML)
public Response getCustomer() {
    Customer customer = customerService.getCustomer();
    return Response.ok(customer).build();
}

这两个将匹配,我们的编写器将用于转换我们的Customer对象

MessageBodReader ...

  

可以使用MessageBodyReaderConsumes实施进行注释,以限制其认为合适的媒体类型。实现Providers合同的MessageBodyReader必须以编程方式在JAX-RS运行时中注册,或者必须使用@Provider注释进行注释,以便在提供程序扫描阶段由JAX-RS运行时自动发现。

@Consumes注释,与作家@Produces相同的交易,刚刚逆转。相同的匹配算法。还有@Provider注释,同样的交易。例如

@Provider
@Consumes(MediaType.APPLICATION_XML)
public class MyJAXBMessageBodyReader 
                   implements MessageBodyReader<Customer> {
    @Override
    public boolean isReadable(Class<Customer> type, Type genericType, 
                              Annotation[] annotations, MediaType mediaType) {

        return type == Customer.class
    }
}

@POST
@Consumed(MediaType.APPLICATION_XML)
public Response createCustomer(Customer customer) {
    customerService.save(customer);
    return Response.created(newCustomerUri).build();
}

阅读器将与我们的方法匹配,并将输入流转换为Customer对象并将其传递给我们的方法。

就最后一句话“扫描阶段”而言,这只是JAX_RS实现扫描我们的包,寻找要管理的组件。这在启动时会发生,基于我们的配置(例如,应扫描哪些包)

只是为了完整......

MessageBodyWriter有另一种方法getSize。如果我们不知道大小,我们可以返回-1,框架将决定我们的大小。

...以及更完整......

如果您想以编程方式注册MessageBodyReaderMessageBodyWriter,请使用registerClient上的ClientBuilder方法(或任何Configurable实例)。