Reputation: 1451
I want to (de-)serialize JSON in multiple different contexts which require slightly different Jackson configurations, in multiple threads. According to resources both on the web and in the class comments, this should be possible using ObjectWriter and ObjectReader constructed from an ObjectMapper which has a "base" configuration. However, I haven't succeeded in building an immutable ObjectWriter from the ObjectMapper -- it seems to change its configuration together with the mapper.
Here's an example that re-configures WRITE_NUMBERS_AS_STRINGS. Please treat this as "just an example" WRT the fact that I need a solution both for the ObjectReader and ObjectWriter, as well as various configuration objects such as @JacksonInject'ed values, not just low-level JSON format options.
public class Main3 {
public static void main(String[] args) throws Exception {
test(false);
test(true);
}
private static void test(boolean enable) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.disable(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS);
ObjectWriter w1 = mapper.writer();
if (enable) {
mapper.enable(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS);
}
ObjectWriter w2 = mapper.writer();
Bean b = new Bean();
b.setX(42);
System.out.println(w1.writeValueAsString(b));
System.out.println(w2.writeValueAsString(b));
}
public static class Bean {
private int x;
/**
* Getter method.
*
* @return the x
*/
public int getX() {
return x;
}
/**
* Setter method.
*
* @param x the x
*/
public void setX(int x) {
this.x = x;
}
}
}
As you can see, I'm running the same test twice, each time creating two ObjectWriters from the same ObjectMapper and serializing a test bean with each of them. In the second run, I'm enabling WRITE_NUMBERS_AS_STRINGS for the second writer. This seems to affect the first writer too.
Expected output:
{"x":42}
{"x":42}
{"x":42}
{"x":"42"}
Actual output:
{"x":42}
{"x":42}
{"x":"42"}
{"x":"42"}
Is there anything else needed to decouple the ObjectWriter from the ObjectMapper? Needless to say, it should be trivial to construct an example based on this one where thread safety is violated, not to mention that the ObjectWriter is obviously NOT immutable.
Upvotes: 1
Views: 9071
Reputation: 116582
For a short answer the issue is that any changes to underlying JsonFactory
, applied via ObjectMapper
, do indeed leak. Not because ObjectWriter
(or ObjectReader
) was mutable, but because they do share mutable factory.
However: there is an alternate way that avoids such visible changes, using with(Feature)
/ without(Feature)
methods:
w = w.with(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS); // or w = w.without(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS);
which works by modifying constructed JsonGenerator
, and NOT reconfiguring JsonFactory
that constructs generators.
Upvotes: 1
Reputation: 8064
The docs do seem to claim readers and writers are immutable. If you found a case where they are not, you should report that as a bug.
In the mean time however you can make a copy of the ObjectMapper
instead and create a writer
from the copy.
Upvotes: 2