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
HttpUrlConnectionProvider.SET_METHOD_WORKAROUND
to trueIn 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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With