mock-server / mockserver

MockServer enables easy mocking of any system you integrate with via HTTP or HTTPS with clients written in Java, JavaScript and Ruby. MockServer also includes a proxy that introspects all proxied traffic including encrypted SSL traffic and supports Port Forwarding, Web Proxying (i.e. HTTP proxy), HTTPS Tunneling Proxying (using HTTP CONNECT) and SOCKS Proxying (i.e. dynamic port forwarding).
http://mock-server.com
Apache License 2.0
4.58k stars 1.07k forks source link

Customize ObjectMapper #547

Closed alonbl closed 5 years ago

alonbl commented 5 years ago

Hi, There is ObjectMapperFactory, however, it is used internally and cannot be customized to allow extensions such as dates and/or field serialization options. It would be nice if the buildObjectMapper can call some user logic to apply additional settings, best to create the actual ObjectMapper as it may require some arguments, then continue with current logic. Maybe better not to have this as singleton and allow customization per client. Thanks!

jamesdbloom commented 5 years ago

It could be a good idea to allow people to provide their own type mappers for JSON objects, however, generally the MockServer works with strings, even if an expectation is JSON the JSON is not serialised into an Object.

Can you explain more about you specific use case so I can't understand why you would need a custom type mapper when MockServer doesn't deserialise / serialise custom types?

alonbl commented 5 years ago

Hi!

I have a library which uses restapi, I would like to mock the server side.

The library uses gson to perform serialization, with custom JsonDeserializer and field naming policy of LOWER_CASE_WITH_UNDERSCORES.

Usage is:

    MyInput input = new Input("x", "y");
    rule.getClient().when(
        HttpRequest.request("/url")
            .withMethod("POST")
            .withBody(JsonBody.json(input)))
        .respond(HttpResponse.response().withStatusCode(200).withBody(
            JsonBody.json(Collections.emptyMap())));

The client is serializing this json per the default mockserver library serialization, while the restapi library is sending a different dialect.

I need to serialize the input per the what the library is producing, in ObjectMapper terms it is:

    return new ObjectMapper()
         .registerModule(new JavaTimeModule()))
         .setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);

It means that the object mapper that is being used for internal mockserver/mockclient interaction should be used only as default, but the mockclient should enable override with a custom mapper.

Of course workaround would be to serialize into string and hand it over, but I believe that the serialization support within the library is good feature and missing this bit of providing my own mapper for data serialization.

If you find this acceptable, the MockServerRule should accept ObjectMapper instance for request/response data serialization, delegate it to MockServerClient which will perform serialization, as I may have two different endpoints with different settings, so it should be per MockServerClient instance. I am unsure how it will work per the singleton such as JsonBody.json.

Another option is to provide optional ObjectMapper instance to each method which performs serialization, example JsonBody.json, this will probably be simplest, however, it not "nice" to the developer.

Thanks!

jamesdbloom commented 5 years ago

Is it not possible to do the following?

ObjectMapper objectMapper = new ObjectMapper()
    .registerModule(new JavaTimeModule()))
 .setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);

MyInput input = new Input("x", "y");
rule.getClient().when(
    HttpRequest.request("/url")
        .withMethod("POST")
        .withBody(JsonBody.json(objectMapper.writeValueAsString(input))))
    .respond(HttpResponse.response().withStatusCode(200).withBody(
        JsonBody.json(Collections.emptyMap())));

With this approach you have 100% control over the serialisation. If the internal Jackson serialiser was overridden then the existing objects may not get serialised correctly.

alonbl commented 5 years ago

On Thu, Nov 1, 2018 at 10:12 PM James D Bloom notifications@github.com wrote:

Is it not possible to do the following? With this approach you have 100% control over the serialisation. If the internal Jackson serialiser was overridden then the existing objects may not get serialised correctly.

Sure! I wrote this initially:

"""

Of course workaround would be to serialize into string and hand it over, but I believe that the serialization support within the library is good feature and missing this bit of providing my own mapper for data serialization. """

However, I think that the feature of the library to serialize/deserialize objects is great, the only missing feature is to control this serialization at client level. In other words the API is well designed, and the missing bit is the assumption of library width serialization.

Thanks!

jamesdbloom commented 5 years ago

I am going to close this issue because I don't feel it is sensible to extend the MockServer serialiser to support generic cases, for the reasons stated above.

martijndwars commented 1 year ago

I'm currently running into the issue that Jackson 2.15 sets a limit on the max length of the string. How can we change this limit, if MockServer provides no access to the underlying ObjectMapper(Factory)?