MessageBody Writer / Reader

我试图让Jersey支持GSON ,为此我已经读过我需要实现自定义MessageBodyWriterMessageBodyReader

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

从文档:

public interface MessageBodyWriter 

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

 public interface MessageBodyReader 

支持将流转换为Java类型的提供程序的合同。 MessageBodyReader实现可以使用Consumes注释,以限制它被认为适合的媒体类型。 实现MessageBodyReader契约的提供者必须以编程方式在JAX-RS运行时中注册,或者必须使用@Provider注释进行注释,以便在提供者扫描阶段由JAX-RS运行时自动发现。

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

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

谢谢。

提供商的合同……

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

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

 @Override public void writeTo(Customer c, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap 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 type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException { JAXBContext context = JAXBContext.newInstance(Customer.class); Unmarshaller unmarshaller = context.createUnmarshaller(); return (Customer)unarshaller.unmarshal(entityStream); } 

MessageBodyWriter …

要添加MessageBodyWriter实现,请使用@Provider注释实现类。 MessageBodyWriter实现可以使用Produces注释,以限制它被认为适合的媒体类型

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

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

 @Provider @Produces(MediaType.APPLICATION_XML) public class MyJAXBMessageBodyWriter implements MessaheBodyWriter { @Override public boolean isWriteable(Class 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 …

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

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

 @Provider @Consumes(MediaType.APPLICATION_XML) public class MyJAXBMessageBodyReader implements MessageBodyReader { @Override public boolean isReadable(Class 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 ,请使用ClientClientBuilder (或任何可Configurable实例)上的register方法。