Jackson ObjectMapper & JsonGenerator - is it thread-safe?
Asked Answered
J

1

5

I currently have a project which uses jackson faster xml to serialize/deserialize POJOs to Json using custom serializers and deserializers. From what I understand, the ObjectMapper is thread-safe once it has been created and configured. However, I have noticed when running tests with JMeter that occasionally the following can happen -

  • Thread 1 enters CustomerSerializer and starts to serialize
  • Thread 2 enters CustomSerializer, interuptting Thread 1, and starts to serialize from start to finish
  • Thread 1 resumes, and the last thing being serialized is missing

It seems to be that the JsonGenerator instance is being reset when the second thread has entered - surely this shouldn't be happening? I have checked several sites and threads to see if there are any settings or features I need to set, but from what I understand the ObjectMapper reuses JsonGenerator instances, could this be the issue?

The following is a snippet from my custom serializer...

@Override
public final void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {

    jsonGenerator.writeStartObject();

    ... Code here ....

    jsonGenerator.writeEndObject();

    closeJsonGenerator(jsonGenerator);
}

And an example of where it is used

SimpleModule sm = new SimpleModule();
sm.addSerializer(new myCustomSerializer());
new ObjectMapper().registerModule(sm)
                  .writeValue(new myObject());
Joinery answered 6/1, 2014 at 18:8 Comment(2)
Please show us how you are using the ObjectMapper and JsonGenerator.Midships
Added a snippet of codeJoinery
M
8

Jackson's ObjectMapper creates a new JsonGenerator on each request for serialization. In that sense, it is guaranteed to be thread safe. The only thing that I can see that might cause the behavior you are seeing is if your CustomSerializer has some instance fields that it is sharing and is doing some kind of internal synchronization.

Midships answered 6/1, 2014 at 18:29 Comment(6)
I will need to take a look at the code (its for a work project), as fasr as I remember there is no where that the JsonGenerator is being shared. However, from what I can see from debugging through the code, the same instance of the CustomSerializer is returned each time?Joinery
@SCassidy1986 That's normal. You're explicitly creating the instance and passing it when registering the module. (Unless you aren't using the same ObjectMapper everywhere.)Midships
I am using the same ObjectMapper - so I'm guessing that each time the CustomSerializer is invoked it's not creating a new JsonGenerator, but rather passing in the same one each time? Or am I getting how the JsonGenerators are created/reused mixed up in my headJoinery
@SCassidy1986 I think you are confusing them. Any call to ObjectMapper#writeValue(..) will internally create a new JsonGenerator and use it. That makes it thread safe. On the other hand, it seems like you are using a single CustomSerializer so that is possibly shared between threads.Midships
Yes, since we use the same instance of the ObjectMapper it is reusing the single instance of the serializer, which appears to be the problem. Is there a way to tell the ObjectMapper to create a serializier each time, rather than cache it and reuse?Joinery
@SCassidy1986 Depending on the use case, you can annotate the field/method you want to serialize with @JsonSerialize(using = CustomSerializer.class)Midships

© 2022 - 2024 — McMap. All rights reserved.