Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Commit

Permalink
Add JAX-RS PATCH annotation (#36)
Browse files Browse the repository at this point in the history
* Add JAX-RS PATCH annotation
  • Loading branch information
EricChristensen authored and b-boogaard committed May 18, 2017
1 parent 531f272 commit e83ff7c
Show file tree
Hide file tree
Showing 16 changed files with 242 additions and 6 deletions.
5 changes: 2 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@

### Enhancements
* Disable the stagemonitor web widget in the service generated by the archetype, as the default configuration.
* Added toString implementation to DelegatingGenericResponse and BuiltGenericResponse.
* Added a PATCH annotation because JAX-rs does not have one.

### Defects Corrected
* Cleaned up dependencies and fixed few minor issues with generated code in archetype.

### Enhancements
* Added toString implementation to DelegatingGenericResponse and BuiltGenericResponse.

## 2.4 - 16 Feb 2017

### Additions
Expand Down
2 changes: 2 additions & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* Jason Gassel [@jpeg][jason-gassel]
* Andy Nelson [@anelson425][andy-nelson]
* Bryan Baugher [@bbaugher][bryan-baugher]
* Eric Christensen [@EricChristensen][eric-christensen]

[john-leacox]: https://github.com/johnlcox
[jacob-williams]: https://github.com/brokensandals
Expand All @@ -25,3 +26,4 @@
[jason-gassel]: https://github.com/jpeg
[andy-nelson]: https://github.com/anelson425
[bryan-baugher]: https://github.com/bbaugher
[eric-christensen]: https://github.com/EricChristensen
1 change: 1 addition & 0 deletions checkstyle-suppressions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
<suppress files="generated-sources" checks=".*"/>
<suppress files="generated-test-sources" checks=".*"/>
<suppress files="com.cerner.beadledom.client.resteasy.ApacheHttpClient4Dot3Engine" checks=".*"/>
<suppress files="com.cerner.beadledom.jaxrs.PATCH" checks="AbbreviationAsWordInName" />
</suppressions>
4 changes: 4 additions & 0 deletions client/beadledom-client-example/example-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
<name>Beadledom Resteasy Client Example API</name>

<dependencies>
<dependency>
<groupId>com.cerner.beadledom</groupId>
<artifactId>beadledom-jaxrs</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.cerner.beadledom.client.example;

import com.cerner.beadledom.client.example.model.JsonOne;
import com.cerner.beadledom.jaxrs.PATCH;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
Expand All @@ -23,4 +24,9 @@ public interface ResourceOne {
@Produces("application/json")
@Consumes("application/json")
JsonOne echo(JsonOne json);

@PATCH
@Produces("application/json")
@Consumes("application/json")
JsonOne patch(JsonOne json);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.cerner.beadledom.client.example;

import com.cerner.beadledom.client.example.model.JsonTwo;
import com.cerner.beadledom.jaxrs.PATCH;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
Expand All @@ -23,4 +24,9 @@ public interface ResourceTwo {
@Produces("application/json")
@Consumes("application/json")
JsonTwo echo(JsonTwo json);

@PATCH
@Produces("application/json")
@Consumes("application/json")
JsonTwo patch(JsonTwo json);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.google.auto.value.AutoValue;

/**
Expand All @@ -10,21 +12,40 @@
* @author John Leacox
*/
@AutoValue
@JsonDeserialize(builder = AutoValue_JsonOne.Builder.class)
public abstract class JsonOne {

public static Builder builder() {
return new AutoValue_JsonOne.Builder();
}

/**
* Creates a new instance of JsonOne.
*/
@JsonCreator
public static JsonOne create(
@JsonProperty("one") String one,
@JsonProperty("hello") String hello) {
return new AutoValue_JsonOne(one, hello);
return builder()
.setOne(one)
.setHello(hello)
.build();
}

@JsonProperty("one")
public abstract String getOne();

@JsonProperty("hello")
public abstract String getHello();

@AutoValue.Builder
@JsonPOJOBuilder(withPrefix = "set")
public abstract static class Builder {

public abstract Builder setOne(String one);

public abstract Builder setHello(String hello);

public abstract JsonOne build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.google.auto.value.AutoValue;

/**
Expand All @@ -10,21 +12,40 @@
* @author John Leacox
*/
@AutoValue
@JsonDeserialize(builder = AutoValue_JsonTwo.Builder.class)
public abstract class JsonTwo {

public static Builder builder() {
return new AutoValue_JsonTwo.Builder();
}

/**
* Creates a new instance of JsonOne.
*/
@JsonCreator
public static JsonTwo create(
@JsonProperty("two") String two,
@JsonProperty("hello") String hello) {
return new AutoValue_JsonTwo(two, hello);
return builder()
.setTwo(two)
.setHello(hello)
.build();
}

@JsonProperty("two")
public abstract String getTwo();

@JsonProperty("hello")
public abstract String getHello();

@AutoValue.Builder
@JsonPOJOBuilder(withPrefix = "set")
public abstract static class Builder {

public abstract Builder setTwo(String two);

public abstract Builder setHello(String hello);

public abstract JsonTwo build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,12 @@ public JsonOne get() {
public JsonOne echo(JsonOne json) {
return json;
}

@Override
public JsonOne patch(JsonOne json) {
return json.builder()
.setHello("Hola1")
.setOne("New Json")
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,12 @@ public JsonTwo get() {
public JsonTwo echo(JsonTwo json) {
return json;
}

@Override
public JsonTwo patch(JsonTwo json) {
return json.builder()
.setHello("Hola2")
.setTwo("New Json")
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,15 @@ class ClientServiceSpec(contextRoot: String, servicePort: Int)
val resourceOne = injector.getInstance(classOf[ResourceOne])
val resourceTwo = injector.getInstance(classOf[ResourceTwo])

val jsonNewOne = JsonOne.create("New Json", "Hola1")
val jsonOne = JsonOne.create("LocalOne", "Hi")
resourceOne.echo(jsonOne) mustBe jsonOne
resourceOne.patch(jsonOne) mustBe jsonNewOne

val jsonNewTwo = JsonTwo.create("New Json", "Hola2")
val jsonTwo = JsonTwo.create("LocalTwo", "Howdy")
resourceTwo.echo(jsonTwo) mustBe jsonTwo
resourceTwo.patch(jsonTwo) mustBe jsonNewTwo
}

it("each client gets its own unique object mapper") {
Expand All @@ -53,7 +57,6 @@ class ClientServiceSpec(contextRoot: String, servicePort: Int)
mapperTwo.isEnabled(SerializationFeature.INDENT_OUTPUT) must be(true)
}


it("provides default object mapper") {
val injector = getInjector(List(new ResourceOneModule, new ResourceTwoModule))

Expand Down
27 changes: 27 additions & 0 deletions docs/source/manual/jaxrs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,33 @@ To include the correlation id in the catalina.out file using log4j, update the l
.. |usageLink| replace:: More on this later
.. _usageLink: `Usage`_

PATCH
--------------

`JAX-RS 2.0 (see section 3.3 for Resource Methods) <http://download.oracle.com/otn-pub/jcp/jaxrs-2_0_rev_A-mrel-eval-spec/jsr339-jaxrs-2.0-final-spec.pdf?AuthParam=1494975982_179302191fa8833291d2b6647856d11b>`_ does not require implementations to support the
`PATCH <https://en.wikipedia.org/wiki/Patch_verb>`_ HTTP method. This is likely due to the fact that ``PATCH`` was introduced in a later `rfc <https://tools.ietf.org/html/rfc5789>`_ that added
the new HTTP method to the already existing HTTP/1.1 specification.

``@PATCH`` was added to `beadledom-jaxrs <https://github.com/cerner/beadledom/tree/master/jaxrs>`_ to allow services to support partial updates without the need of
overloading ``@POST``. The annotation has no opinion on how the service decides to implement the
resource performing the ``PATCH`` operation. Implementing services have the freedom to support `JSON
Patch <https://tools.ietf.org/html/rfc6902>`_ and/or `JSON Merge Patch <https://tools.ietf.org/html/rfc7386>`_.

As long as a service has ``beadledom-jaxrs`` as a dependency ``@PATCH`` can be used just like any of the
HTTP method annotations defined by JAX-RS. Below is a small example of ``@PATCH`` being used in an
interface for a resource.

.. code-block:: java
@PATCH
@Path("path/to/patch")
@Produces(MediaType.APPLICATION_JSON)
public Response patch(
@PathParam("id") final Long id,
@ApiParam(value = "changes to make to the object with the specified id")
PatchObject patchObject);
.. _RFC: https://tools.ietf.org/html/rfc5789
Download
--------

Expand Down
20 changes: 20 additions & 0 deletions jaxrs/src/main/java/com/cerner/beadledom/jaxrs/PATCH.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.cerner.beadledom.jaxrs;

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;

/**
* Indicates that the annotated method responds to HTTP PATCH requests.
*
* @author Eric Christensen
* @since 2.5
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@HttpMethod("PATCH")
public @interface PATCH {
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ public class FakeModel {
@JsonProperty("inner_models")
public List<FakeInnerModel> innerModels;

public FakeModel() {

}

public FakeModel(
String id, String name, int times, List<String> tags, List<FakeInnerModel> innerModels) {
this.id = id;
Expand All @@ -37,6 +41,32 @@ public FakeModel(
this.innerModels = innerModels;
}

public FakeModel setId(String id) {
this.id = id;
return this;
}

public FakeModel setName(String name) {
this.name = name;
return this;
}

public FakeModel setTimes(int times) {
this.times = times;
return this;
}

public FakeModel setTags(List<String> tags) {
this.tags = tags;
return this;
}

public FakeModel setInnerModels(
List<FakeInnerModel> innerModels) {
this.innerModels = innerModels;
return this;
}

@JsonProperty("id")
public String getId() {
return id;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.cerner.beadledom.jaxrs.provider;

import com.cerner.beadledom.jaxrs.PATCH;

import javax.ws.rs.Consumes;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/fakeResource")
public class FakeResource {

@PATCH
@Path("/Patch")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response fakePatch(FakeModel model) {
model.setId("newId");
model.setName("newName");
return Response.ok(model).build();
}
}
Loading

0 comments on commit e83ff7c

Please sign in to comment.