I am working on a REST API implementation using Jersey. For PATCH
(partial updates), I have implemented my own custom implementation of PATCH
since Jersey does not support it.
Now I am trying to figure out how to write functional tests around that implementation. I am using jersey test framework for other methods ( PUT
, POST
, GET
, DELETE
) that has that support available in that framework.
Is there a way where in I can extend jersey test framework implementation to write my functional tests for PATCH
? If not, are there any other test frameworks available that I can use to test my Jersey PATCH
implementation?
If anyone can provide any examples, that would be great.
Assuming your implementation consists of a custom annotation like this
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;
@HttpMethod("PATCH")
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PATCH {}
Trying to do something like this with the Client
String response = target.request().method("PATCH", Entity.text("Hello"), String.class);
by default is not supported, and will an exception like
java.net.ProtocolException: Invalid HTTP method: PATCH
This is not a problem with the Client
API directly, but with the lower level Java APIs. Seems to be some security restriction.
With the Client API we can override this by setting a property
In the JerseyTest
, one way to configure the Client
is to override configureClient
, and set the property with the ClientConfig
. You could just as easily set the property on the Client
itself, but staying in the spirit of the JerseyTest
framework (where we don't need to explicitly access the Client
, the example below will just just override the method
public class PatchTest extends JerseyTest {
@Path("patch")
public static class PatchResource {
@PATCH
@Produces(MediaType.TEXT_PLAIN)
public String getPatch(String request) {
return "Patched " + request;
}
}
@Override
protected void configureClient(final ClientConfig config) {
config.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true);
}
@Override
public Application configure() {
return new ResourceConfig(PatchResource.class);
}
@Test
public void doPatchTest() {
WebTarget target = target("patch");
String response = target.request().method("PATCH", Entity.text("Hello"), String.class);
Assert.assertEquals("Patched Hello", response);
System.out.println(response);
}
}
To send the HTTP PATCH
via JAX RS Client API
without any extra configuration:
client.target("$baseUrl$restUsersUrl/$userId")
.request("application/json")
.build("PATCH", Entity.entity(json2Update, MediaType.APPLICATION_JSON))
.invoke()
Annotation @PATCH
is now available in JAX-RS 2.1. You can implement this HTTP method on the server side like:
@PATCH
public Response updateResource() { ... }
As for the client side, you can do something like:
Response r = ClientBuilder.newClient()
.target("http://localhost:8080/patch")
.request()
.build("PATCH", Entity.text("patch"))
.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true)
.invoke();
Where SET_METHOD_WORKAROUND
is used to avoid the protocol exception, as indicated by @peeskillet:
java.net.ProtocolException: Invalid HTTP method: PATCH
With simple Strings this works for me. But does anyone know how to do this when the Patch method does not accept and return a simple String? See my example below. The return type in the Response differs from the type of the passed argument. Both of which are not simple types. Instead of a 200, I always get a 400 and/or the message that it cannot construct the ObjectPatch instance. And I understand that, since it is an interface with only an apply method. But somehow on runtime it manages to construct an AttentionPatchResource object from it anyway. Unfortunately not when using the JerseyTest framework.
@PATCH
@Path("/something")
@Produces(MediaType.APPLICATION_JSON)
@Consumes({ PatchMediaTypes.APPLICATION_MERGE_PATCH_JSON, PatchMediaTypes.APPLICATION_JSON_PATCH })
public Response updateAttention( //
@Parameter(schema = @Schema(implementation = AttentionPatchResource.class)) ObjectPatch patch) {
Attention attention = attentionService.find();
AttentionPatchResource patchResource = attentionAdapter.toPatchResource(attention);
AttentionPatchResource patchedResource = patch.apply(patchResource);
Attention patchedAttention = attentionAdapter.fromPatchResource(attention, patchedResource);
AttentionResource resource = attentionAdapter.toResource(patchedAttention);
return Response.status(Status.OK).entity(resource).build();
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.