cfeduke
cfeduke

Reputation: 23226

Jersey, ContainerRequestFilters and DELETE

I'm using Jersey 1.11 and trying to model both POST and DELETE methods in my RESTful resource.

The problem I am encountering is in my unit tests. I cannot use the delete method of WebResource and still expect a ContentResponse instance (there are workarounds but since I will at some point use a Rails front end I'd rather sort this out now). So I'm trying to use POST with the PostReplaceFilter and have variously tried submitting form and query _method parameters (set to DELETE) as well as the X-HTTP-Method-Override header.

I am configuring the PostReplaceFilter in web.xml as such:

<servlet-name>SomeName</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
  <param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
  <param-value>com.sun.jersey.api.container.filter.PostReplaceFilter</param-value>
</init-param>

My REST resource looks like this:

@Controller
@Scope("prototype")
@Path("{apiVersion}/push/")
public class Push extends BaseRequest {
  @POST
  @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
  @Produces(MediaType.APPLICATION_JSON)
  @Path("registration")
  public Response create(@FormParam(REGISTRATION_ID_FIELD) String registrationId) throws Exception {
    /* omitted; this method ends in a 200 OK */
  }

  @DELETE
  @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
  @Path("registration")
  public Response destroy(@FormParam(REGISTRATION_ID_FIELD) String registrationId) throws Exception {
    /* omitted; this method ends in a 204 NO CONTENT */
  }

My unit test always invokes the first create method as if the PostReplaceFilter is having no effect:

 private WebResource.Builder prepare(String path, String method) {
    return resource().path(path)
            .queryParam("_method", method)
            .cookie(new Cookie(Report.DEVICE_COOKIE_NAME, TEST_DEVICE_ID))
            .cookie(new Cookie(Report.TOKEN_COOKIE_NAME, TEST_TOKEN));
 }

 @Test
 public void destroyShouldEliminateAnyPushRegistrationAndTokenForADevice() throws Exception {
    // mocks are setup here
    MultivaluedMap<String, String> formData = createFormData(registrationId);
    ClientResponse response = prepare("/1.0/push/registration", "DELETE")
        .header("X-HTTP-Method-Override", "DELETE")
        .post(ClientResponse.class, formData);
    assertThat(response.getStatus(), is(204));
    // mocks are verified here
  }

I know the first method is being invoked because create returns a 200 while the destroy method returns 204 and the assertThat line is failing due to a 200 status (additionally my expected methods on my mocks are not being invoked).

My unit test inherits from JerseyTest and uses the Grizzly2 Web Container.

Upvotes: 1

Views: 2131

Answers (1)

cfeduke
cfeduke

Reputation: 23226

My co-worker pointed out that the web.xml is not actually used as part of the test stack. Instead I needed to initialize the filters programmatically; in our case our base test inherited from JerseyTest and overwrote the configure method:

@Override
protected AppDescriptor configure() {
    return new WebAppDescriptor.Builder("com.yourproject.blah")
            .initParam("com.sun.jersey.spi.container.ContainerRequestFilters", 
                "com.sun.jersey.api.container.filter.PostReplaceFilter")
            .servletClass(SpringServlet.class)
            .build();
}

Upvotes: 2

Related Questions