How to have a @PATCH annotation for JAX-RS?
Asked Answered
C

6

76

JAX-RS has annotations for HTTP verbs such as GET (@GET) and POST (@POST) but there is no @PATCH annotation. How can I have an annotation for the PATCH HTTP verb?

Something like the following:

@PATCH
public Response someCode() {
    // Code to handle the request
}
Chrysa answered 27/7, 2013 at 11:18 Comment(1)
JAX-RS 2.1 supports @PATCH out-of-the-box.Payola
C
80

I got answer here.

One will just have to define a custom Patch annotation, what that means is that you will have to write a PATCH.java file with following code:

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

Import the package containing PATCH.java and then you can use it like other HTTP method annotations:

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

I used this @PATCH to send some JSON to my REST service.

Chrysa answered 27/7, 2013 at 11:37 Comment(9)
I used this @PATCH to send some JSON to my REST service and it worked like a charm. You can't do this using GET request, so there is no doubt it getting default to GET request.Chrysa
@LutzHorn I am using this @PATCH 'alongside' @GET using the same @Path with no troubles so far, using Jersey 1.17.1Xuanxunit
I have a problem with this solution. Jersey treats method annotated with @PATCH as resource locator method. What I possibly missed?Mangonel
How is PATCH support still not integrated in javax.ws.rs? I mean, really.Primus
@Jorn I am amazed too.Chrysa
@VishalDevgire, can you publish some more code if possible ?Bellboy
JAX-RS 2.1 supports @PATCH out-of-the-box :)Payola
Unfortunately, I believe the first non milestone release was in August. My boss doesn't want to use it because of this. I don't either. Hopefully he'll like this slick workaround and let me keep my patches. arrr!Remove
@patryk I have the same problem, how did you manage to solve this?Sagerman
P
27

Using JAX-RS 2.1?

JAX-RS 2.1 added @PATCH to the list of supported HTTP methods.

Using Swagger?

When using Swagger to document a REST API, you could use the existing @PATCH annotation defined in the io.swagger.jaxrs package.

Using Jersey and Dropwizard?

Dropwizard defines a @PATCH annotation in the io.dropwizard.jersey package.

Write your own

If the above mentioned approaches don't work for you, you can write your own @PATCH annotation:

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

The @HttpMethod annotation is used to associate the name of a HTTP method with an annotation, creating a what the JAX-RS specification calls resource method designator.

Your own @PATCH annotation should work fine in Swagger.

Payola answered 8/4, 2016 at 13:20 Comment(0)
A
5

In Jersey this will work just fine, but when using Jersey Client to test your resource class, you will get exceptions:

java.net.ProtocolException: Invalid HTTP method: PATCH

There is a workaround for this, by setting client property

HttpUrlConnectorProvider.SET_METHOD_WORKAROUND 

But wait, then you will end up with the following exception:

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

So there is no other way than changing to the Apache HTTP client library, using Jersey version 2.10, its easy to configure to use Apache HTTP client, you only need to override the client config method in your test class that extends JerseyTest.

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

And you need to also add another Maven dependency, jersey-apache-connector and jersey-test-framework-provider-external, see Jersey doc

Allometry answered 29/7, 2014 at 6:54 Comment(0)
A
1

JAX-RS API 2.0.1 doesn't have PATCH. But, looking at JAX-RS API 2.2-SNAPSHOT code, PATCH is now included. The code is:

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

Here is the link.

You might use the same codes for remedy until 2.2 is out. For HttpMethod.PATCH, just replace it with "PATCH".

Alb answered 23/8, 2017 at 5:46 Comment(0)
C
0

If you are using CXF 3.1.2 or later (source), you can use org.apache.cxf.jaxrs.ext.PATCH.

Cyclops answered 19/12, 2017 at 10:37 Comment(0)
S
-1

This is my implementation of PATCH with jax-rs 2.2

Person class

public class Person {


    private Integer id;
    @NotEmpty
    @Size(min = 2)
    private String name;
    @NotEmpty
    @Size(min = 2)
    private String surname;

    // getters and setters
}

Person 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);
}

PersonDB

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);
    }
}

Test the API:

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

Here you can find the project with full example

See also RFC for further explanations

Songwriter answered 22/10, 2021 at 9:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.