23

I need to configure the underlying Jackson ObjectMapper in REST Assured. I am writing REST API tests using REST Assured and I need to define some filters to register with the ObjectMapper that is used to serialize my objects to JSON:

    String newTestSuite = "{\"name\":\"Added through Rest API\",\"description\":\"Test Description\",\"steps\":[]}";

    FilterProvider filters = new SimpleFilterProvider().addFilter("createNewTestSuite", new NewTestSuiteFilter());
    ObjectMapper om = new ObjectMapper();
    om.setFilters(filters);

    try {
        TestSuite ts = om.readValue(newCaspianTest, TestSuite.class);

        RequestSpecification requestSpec = new RequestSpecBuilder()
            .setBaseUri("https://somesite.com")
            .setBody(ts)
            .setUrlEncodingEnabled(false)
            .build();

        ResponseSpecification responseSpec = new ResponseSpecBuilder()
            .expectStatusCode(200)
            .expectStatusLine(Matchers.containsString("200 OK"))
            .build();

        RestAssured.given()
            .auth().basic("testUser","testPassword")
            .spec(requestSpec)
            .log().all()
            .post("/restendpoint")
                .then()
                .log().all()
                .spec(responseSpec);

    } catch(JsonParseException jpe) {

    } catch(JsonMappingException jme) {

    } catch(IOException ioe) {

    }
}

}

Selena
  • 2,208
  • 8
  • 29
  • 49

4 Answers4

33

You can try this:

RestAssured.config = RestAssuredConfig.config().objectMapperConfig(new ObjectMapperConfig().jackson2ObjectMapperFactory(
new Jackson2ObjectMapperFactory() {
        @Override
        public ObjectMapper create(Class aClass, String s) {
            FilterProvider filter = new SimpleFilterProvider().addFilter(...);
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.setFilters(filter);
            return objectMapper;
        }
    }
));
Misha Brukman
  • 12,938
  • 4
  • 61
  • 78
sanj
  • 381
  • 3
  • 3
  • I am trying this solution out right now, but I have one question -- It's not possible to use a type parameter with the Class argument here is it? I have to use the raw class type? – Selena Aug 01 '14 at 12:14
  • This worked great! I did have an issue with Eclipse complaining that I had not overridden a superclass method, but I found that my java compiler compliance level was set to 1.5 and support for the Override annotation on implemented methods from an interface was not added until java 1.6. Once I changed my Eclipse preferences, the error went away. – Selena Aug 01 '14 at 13:23
  • 1
    I've tried this but my filter is never called. I've gone through the Jackson code and, while I see my filter being passed around as part of the FilterProvider in the configuration, the filter itself is never invoked. Did you have any similar difficulties? – torngat Apr 23 '15 at 17:57
  • Ok, I've found that I have to override the annotation introspector since my classes do not refer to this filter in any way. However, this raises another question for me that I've posted here [http://stackoverflow.com/questions/29833259/jackson-how-to-add-property-filter-without-overriding-annotation-filters] – torngat Apr 23 '15 at 20:06
10

This will give you an object mapper that does not explode when the back end developer decides to add a new field.

RestAssured.config = RestAssuredConfig.config().objectMapperConfig(new ObjectMapperConfig().jackson2ObjectMapperFactory(
    new Jackson2ObjectMapperFactory() {
      @Override
      public ObjectMapper create(Type cls, String charset) {
        ObjectMapper om = new ObjectMapper().findAndRegisterModules();
        om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return om;
      }          

    }
));
AdrianHHH
  • 13,492
  • 16
  • 50
  • 87
Jason Henriksen
  • 101
  • 1
  • 4
3

Given the context for which Rest Assured is used, often times you'll want to modify or provide the ObjectMapper used for some request, but not all of them.

You can achieve this by using the methods:

A classic use case, as @jason-henriksen mentioned is to

  • Allow unknown properties to be ignored
  • Ignore properties defined in your ReturnedType class that are not marked with @JsonIgnore without throwing an Exception during the deserialization (useful when you have no control/ can't modify that ReturnedType class 1)

This can be done with:

RequestSpecification request = ...;
io.restassured.mapper.ObjectMapper objectMapper = new Jackson2Mapper(((type, charset) -> {
    com.fasterxml.jackson.databind.ObjectMapper om = new ObjectMapper().findAndRegisterModules();
    om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    return om;
}));
ReturnType response = request.get().as(ReturnType.class, objectMapper);

1 You can also achieve this by configuring your ObjectMapper with Jackson MixIns.

absurd
  • 31
  • 2
  • This solution worked perfectly for me! In my case, the deserialization was failing at .as(...) and passing in a custom objectMapper was the easiest solution that didn't require changing it everywhere. – swiftest May 20 '21 at 17:38
2

@sanj's answer was very helpful. I had to modify it slightly because I'm using RestAssuredMockMvc.

This is how I configure RestAssuredMockMvc to use snake_case instead of CamelCase:

RestAssuredMockMvc.config = RestAssuredMockMvcConfig.config().objectMapperConfig(new ObjectMapperConfig().jackson2ObjectMapperFactory(
            (type, s) -> {
                ObjectMapper objectMapper = new ObjectMapper();
                objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
                return objectMapper;
            }
    ));
Bram
  • 988
  • 7
  • 10