【问题标题】:How to have a @PATCH annotation for JAX-RS?如何为 JAX-RS 提供 @PATCH 注释?
【发布时间】:2013-07-27 11:18:21
【问题描述】:

JAX-RS 具有 HTTP 动词注释,例如 GET (@GET) 和 POST (@POST),但没有 @PATCH 注释。如何为PATCH HTTP 动词添加注释?

类似于以下内容:

@PATCH
public Response someCode() {
    // Code to handle the request
}

【问题讨论】:

  • JAX-RS 2.1 支持@PATCH 开箱即用。

标签: java jax-rs


【解决方案1】:

我得到了答案here

你只需要定义一个自定义的补丁注解,这意味着你必须使用以下代码编写一个 PATCH.java 文件:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@HttpMethod("PATCH")
public @interface PATCH {
}

导入 包含 PATCH.java 的包,然后您可以像使用其他 HTTP 方法注释一样使用它:

@PATCH
@Path("/data/{keyspace}")
@Produces({ "application/json" })
public void patchRow(@PathParam("keyspace") String keyspace, String body) 
throws Exception

我使用这个@PATCH 将一些 JSON 发送到我的 REST 服务。

【讨论】:

  • 我使用这个@PATCH 将一些 JSON 发送到我的 REST 服务,它就像一个魅力。您不能使用 GET 请求来执行此操作,因此毫无疑问它会默认为 GET 请求。
  • @LutzHorn 我正在使用这个 @PATCH 'alongside' @GET 使用相同的 @Path 到目前为止没有任何问题,使用 Jersey 1.17.1
  • 我对这个解决方案有疑问。 Jersey 将带有 @PATCH 注释的方法视为资源定位器方法。我可能错过了什么?
  • javax.ws.rs 中还没有集成 PATCH 支持吗?我是说,真的。
  • JAX-RS 2.1 支持 @PATCH 开箱即用 :)
【解决方案2】:

使用 JAX-RS 2.1?

JAX-RS 2.1@PATCH 添加到支持的 HTTP 方法列表中。

使用 Swagger?

当使用 Swagger 记录 REST API 时,您可以使用在 io.swagger.jaxrs 包中定义的现有 @PATCH 注释。

使用 Jersey 和 Dropwizard?

Dropwizardio.dropwizard.jersey 包中定义了一个@PATCH 注释。

自己写

如果上述方法不适合你,你可以自己写@PATCH注解:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@HttpMethod("PATCH")
public @interface PATCH { }

@HttpMethod 注解用于将 HTTP 方法的名称与注解相关联,创建 JAX-RS 规范所称的资源方法指示符

你自己的 @PATCH 注释应该在 Swagger 中 work fine

【讨论】:

    【解决方案3】:

    在 Jersey 中这可以正常工作,但是在使用 Jersey Client 测试您的资源类时,您会遇到异常:

    java.net.ProtocolException: Invalid HTTP method: PATCH
    

    有一个解决方法,通过设置客户端属性

    HttpUrlConnectorProvider.SET_METHOD_WORKAROUND 
    

    但是等等,那么你最终会遇到以下异常:

    javax.ws.rs.ProcessingException: java.net.ProtocolException: HTTP method PATCH doesn't support output
    

    所以除了使用 Jersey 2.10 版更改为 Apache HTTP 客户端库之外别无他法,它易于配置以使用 Apache HTTP 客户端,您只需要覆盖扩展 @987654325 的测试类中的客户端配置方法@。

    @Override
    protected void configureClient(ClientConfig config) {
      config.register(CustomJacksonJsonProvider.class);
      ConnectorProvider connectorProvider = new ApacheConnectorProvider();
      config.connectorProvider(connectorProvider);
    }
    

    您还需要添加另一个 Maven 依赖项,jersey-apache-connectorjersey-test-framework-provider-external,请参阅 Jersey doc

    【讨论】:

      【解决方案4】:

      JAX-RS API 2.0.1 没有 PATCH。但是,查看 JAX-RS API 2.2-SNAPSHOT 代码,现在包含 PATCH。代码是:

      @Target({ElementType.METHOD})
      @Retention(RetentionPolicy.RUNTIME)
      @HttpMethod(HttpMethod.PATCH)
      @Documented
      public @interface PATCH {
      }
      

      这里是link

      在 2.2 发布之前,您可以使用相同的代码进行补救。对于 HttpMethod.PATCH,只需将其替换为“PATCH”即可。

      【讨论】:

        【解决方案5】:

        如果您使用的是 CXF 3.1.2 或更高版本 (source),则可以使用 org.apache.cxf.jaxrs.ext.PATCH

        【讨论】:

          【解决方案6】:

          这是我使用 jax-rs 2.2 实现的 PATCH

          人物类

          public class Person {
          
          
              private Integer id;
              @NotEmpty
              @Size(min = 2)
              private String name;
              @NotEmpty
              @Size(min = 2)
              private String surname;
          
              // getters and setters
          }
          

          个人 REST API

          /**
           * see https://tools.ietf.org/html/rfc6902 for further explanations
           */
          @PATCH
          @Produces(MediaType.APPLICATION_JSON)
          @Consumes(MediaType.APPLICATION_JSON)
          @Path("/{id}")
          public void modify(@PathParam("id") int id,
                             JsonArray input) {
              personDB.update(id, input);
          }
          

          个人数据库

          public void update(int id, final JsonArray input) {
          
              final Person person = people.stream()
                      .filter(i -> i.getId() == id)
                      .findAny()
                      .orElseThrow(NotFoundException::new);
          
              final JsonObject source; // json object person representation
          
              try (JsonReader jsonReader = Json.createReader(new StringReader(Json.createValue(JsonbBuilder.create().toJson(person)).getString()))) {
                  source = jsonReader.readObject();
              }
          
              final JsonObject output; // apply update to source object
              try {
                  output = Json.createPatch(input).apply(source);
              } catch (JsonException e) {
                  throw new BadRequestException(e.getMessage());
              }
          
              try (final Jsonb jsonb = JsonbBuilder.create()) { // apply updates to final object
                  final Person target = jsonb.fromJson(output.toString(), Person.class);
                  person.setName(target.getName());
                  person.setSurname(target.getSurname());
              } catch (Exception e) {
                  throw new InternalServerErrorException(e);
              }
          }
          

          测试 API:

          PATCH /person/{id}
          [
              {
                  "op": "add",
                  "path": "/name",
                  "value": "John"
              }
          ]
          

          Here你可以找到完整示例的项目

          更多解释请参见RFC

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-10-22
            • 1970-01-01
            • 2016-07-13
            • 1970-01-01
            • 2012-01-28
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多