PATCH方法是最不受欢迎的HTTP方法之一,因为直到最近才真正没有一种标准的PATCH格式。 一段时间以来,它已经针对JSON进行了标准化,因此有很多库可以为您完成繁重的工作。 出于本博客的目的,我将使用json-patch,尽管可以很容易地将这种特定的实现方式适应您选择的补丁库。

每个正常值可以让资源和Bean类不受干扰。 在此示例代码中,我们有一个简单的资源,该资源知道如何返回原始对象,并且该资源允许您执行PATCH方法。 请注意,patch方法仅接受bean对象,这是因为我们需要做一些魔术才能对补丁进行预处理。

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;@Path("service")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class Service {@GETpublic Bean get() {return new Bean(true);}@PATCH@Consumes("application/json-patch+json")public Bean patch(Bean input) {System.out.println(input.getMessage() + "  " + input.getTitle());return input;}}import java.util.ArrayList;
import java.util.List;public class Bean {private String title = "title";private String message = "message";private List<String> list = new ArrayList<String>();public Bean() {this(false);}public Bean(boolean init) {if (init) {title = "title";message = "message";list.add("one");list.add("two");}}public void setList(List list) {this.list = list;}public List getList() {return list;}public void setTitle(String title) {this.title = title;}public String getTitle() {return title;}public void setMessage(String message) {this.message = message;}public String getMessage() {return message;}}

因此,对于这个示例,我们必须创建@PATCH批注,幸运的是,JAX-RS为此目的包含了一个扩展元批注。 我们还将使用@NameBinding因为此示例使用的是JAX-RS 2.0,因此我们可以@NameBinding连接过滤器。

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;import javax.ws.rs.HttpMethod;
import javax.ws.rs.NameBinding;@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@HttpMethod("PATCH")
@Documented
@NameBinding
public @interface PATCH {
}

因此,这里是ReaderInterceptor的实现,该实现将处理传入的流并将其替换为修补版本。 请注意,还使用@PATCH对该类进行了注释,以使@NamedBinding魔术起作用,并且还缺少许多错误处理,因为这是一个简单的POC。

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;import com.github.fge.jsonpatch.JsonPatch;
import com.github.fge.jsonpatch.JsonPatchException;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;import java.lang.annotation.Annotation;
import java.lang.reflect.Method;import javax.ws.rs.GET;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.ReaderInterceptor;
import javax.ws.rs.ext.ReaderInterceptorContext;import org.glassfish.jersey.message.MessageBodyWorkers;@Provider
@PATCH
public class PatchReader implements ReaderInterceptor {private UriInfo info;private MessageBodyWorkers workers;@Contextpublic void setInfo(UriInfo info) {this.info = info;}@Contextpublic void setWorkers(MessageBodyWorkers workers) {this.workers = workers;}@Overridepublic Object aroundReadFrom(ReaderInterceptorContext readerInterceptorContext) throws IOException,WebApplicationException {// Get the resource we are being called on, // and find the GET methodObject resource = info.getMatchedResources().get(0);Method found = null;for (Method next : resource.getClass().getMethods()) {if (next.getAnnotation(GET.class) != null) {found = next;break;}}if (found != null) {// Invoke the get method to get the state we are trying to patch//Object bean;try {bean = found.invoke(resource);} catch (Exception e) {throw new WebApplicationException(e);}// Convert this object to a an aray of bytes ByteArrayOutputStream baos = new ByteArrayOutputStream();MessageBodyWriter<? super Object> bodyWriter =workers.getMessageBodyWriter(Object.class, bean.getClass(), new Annotation[0], MediaType.APPLICATION_JSON_TYPE);bodyWriter.writeTo(bean, bean.getClass(), bean.getClass(), new Annotation[0], MediaType.APPLICATION_JSON_TYPE,new MultivaluedHashMap<String, Object>(), baos);// Use the Jackson 2.x classes to convert both the incoming patch  // and the current state of the object into a JsonNode / JsonPatchObjectMapper mapper = new ObjectMapper();JsonNode serverState = mapper.readValue(baos.toByteArray(), JsonNode.class);JsonNode patchAsNode = mapper.readValue(readerInterceptorContext.getInputStream(), JsonNode.class);JsonPatch patch = JsonPatch.fromJson(patchAsNode);try {// Apply the patchJsonNode result = patch.apply(serverState);// Stream the result & modify the stream on the readerInterceptorByteArrayOutputStream resultAsByteArray = new ByteArrayOutputStream();mapper.writeValue(resultAsByteArray, result);readerInterceptorContext.setInputStream(new ByteArrayInputStream(resultAsByteArray.toByteArray()));// Pass control back to the Jersey codereturn readerInterceptorContext.proceed();} catch (JsonPatchException e) {throw new WebApplicationException(Response.status(500).type("text/plain").entity(e.getMessage()).build());}} else {throw new IllegalArgumentException("No matching GET method on resource");}}
}

因此,一旦部署完成,就可以开始处理数据,因此原始消息是:

{"list" : ["one","two"],"message" : "message","title" : "title"
}

因此,如果应用以下修补程序,则返回的结果是:

[{"op" : "replace","path" : "/message","value" : "otherMessage"},{"op" : "add","path" : "/list/-","value" : "three"}
]{"list" : ["one","two","three"],"message" : "otherMessage","title" : "title"
}

此示例说明,遵循简单的编码模式并使用简单的注释,将PATCH支持添加到您的类中相对比较简单。 这样,由于实现仅可以委托给您现有的PUT方法,因此PATCH支持变得微不足道。

更新: Jersey团队的Mirsolav Fuksa提醒我,为了使此实现符合PATCH RFC,它应在客户端执行OPTIONS请求时提供Accept-Patch标头。 您可以使用简单的CotnainerResponseFilter来做到这一点:

import java.io.IOException;import java.util.Collections;import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;@Provider
public class OptionsAcceptHeader implements ContainerResponseFilter {@Overridepublic void filter(ContainerRequestContext requestContext,ContainerResponseContext responseContext) throws IOException {if ("OPTIONS".equals(requestContext.getMethod())) {if (responseContext.getHeaderString("Accept-Patch")==null) {responseContext.getHeaders().put("Accept-Patch", Collections.<Object>singletonList("application/json-patch+json"));  }}}
}
参考:来自Gerard Davison博客博客的JCG合作伙伴 Gerard Davison 对JAX-RS 2.0的透明PATCH支持 。

翻译自: https://www.javacodegeeks.com/2014/02/transparent-patch-support-in-jax-rs-2-0.html

JAX-RS 2.0中的透明PATCH支持相关推荐

  1. input发送a.jax_JAX-RS 2.0中的透明PATCH支持

    input发送a.jax PATCH方法是最不受欢迎的HTTP方法之一,因为直到最近才真正没有一种标准的PATCH格式. 一段时间以来,它已经针对JSON进行了标准化,因此有很多库可以为您完成繁重的工 ...

  2. 在Entity Framework 4.0中使用 Repository 和 Unit of Work 模式

    [原文地址]Using Repository and Unit of Work patterns with Entity Framework 4.0  [原文发表日期] 16 June 09 04:0 ...

  3. Android RxJava 2.0中backpressure(背压)概念的理解

    英文原文:https://github.com/ReactiveX/RxJava/wiki/Backpressure Backpressure(背压.反压力) 在rxjava中会经常遇到一种情况就是被 ...

  4. RxJava 2.0中backpressure(背压)概念的理解

    英文原文:https://github.com/ReactiveX/RxJava/wiki/Backpressure Backpressure(背压.反压力) 在rxjava中会经常遇到一种情况就是被 ...

  5. Hhadoop-2.7.0中HDFS写文件源码分析(二):客户端实现(1)

    一.综述 HDFS写文件是整个Hadoop中最为复杂的流程之一,它涉及到HDFS中NameNode.DataNode.DFSClient等众多角色的分工与合作. 首先上一段代码,客户端是如何写文件的: ...

  6. datax底层原理_手把手实现Datax3.0中的传输通道

    Datax的整体框架我们已经大体了解.这次来分析一下reader到writer中间数据的传输层. 这次采取另外一种方式,我们把代码抽取,自己实现一个通道 1-首先是定义一个接口代表传输的每一条数据pu ...

  7. 艾伟_转载:.NET 4.0中数组的新增功能

    1.两数组是否"相等"? 在实际开发中,有时我们需要比对两个数组是否拥有一致的元素,例如,以下两个数组由于拥有相同的元素,因此被认为是相等的: int[] arr1 = new i ...

  8. JDBC 2.0中的高级数据类型

    JDBC 2.0中提供了对SQL3标准中引入的新的数据类型,如Blob(binary large object).Clob(character large object).Array 对象.REF(对 ...

  9. 在Eclipse 2.0中使用版本控制系统CVS

    董向辉 (xianghui.dong@mail.ia.ac.cn) 2002 年 7 月 2002年6月28日,Eclipse 2.0正式版已经正式完成,这将是Java开发工具历史上的一个重要事件,E ...

最新文章

  1. java se 6u111_linux下查看已经安装的jdk 并卸载jdk
  2. HashMap 怎么 hash?又如何 map?
  3. explain查看mysql语句的执行效率
  4. Visual Studio Code 快捷键的设置
  5. OllyDBG 入门之四--破解常用断点设
  6. react中创建一个组件_如何使用React和MomentJS创建一个Countdown组件
  7. winform窗体中嵌入显示Excel文件
  8. Java零基础系列001——第一个程序
  9. 第 7 章 Neutron - 072 - 详解 ML2 Core Plugin(II)
  10. Log4j(三)——Log4j配置文件位置详解
  11. 一键将知网CAJ文件转换成带书签的PDF
  12. bulk of the 用法_高中英语 | 10大词类详解+用法+考点,必须牢记,超全讲解!
  13. 有关电影《邪不压正》和姜文系列
  14. python怎么判断倍数_如何判断一个数是否是七的倍数?
  15. Free Lossless Audio Codec
  16. 135、137、138、139、445等端口解释和关闭方法
  17. 从业务架构师角度看区块链为什么以及如何改变世界
  18. 零基础HTML入门教程(11)——换行br
  19. 国家二级计算机考试大纲,计算机国家二级考试大纲.doc
  20. Linux运维学习笔记(一)

热门文章

  1. nacos 读取纯数字字符 出错 @value
  2. springboot 页面下载文件 网页下载文件功能 文件放resourcce下面
  3. jvm(2)-java内存区域
  4. starter_您是否尝试过MicroProfile Starter?
  5. python kotlin_Java和Python中类似Kotlin的生成器,续:附加参数
  6. jboss7.0.2_红帽JBoss企业应用平台7.0 ALPHA发布了!
  7. hibernate性能_改善Hibernate应用程序性能的7种方法
  8. 基于按位与的 就散策略_比较散列策略
  9. k8s中graphite_在Graphite中存储Hystrix的几个月历史指标
  10. 启动jboss_3种启动JBoss BPM流程的基本方法