问题
I am using Jackson 2.10.5 to serialize the same java.util.Date
object three times.
- The first time, with a basic Jackson
ObjectMapper
. I see the timestamp. - Then I configure the same
ObjectMapper
, and rewrite. I get the same result. - Then I construct a new
ObjectMapper
, configure it the same way. I get a different result, the class name and the timestamp in a JSON list.
The configuration is intended to tell the ObjectMapper
to include the class name of every object except java.util.Date
as a JSON property.
So I have two questions. The first is why is the date object serialized differently in the third case? Any advice on using the PolymorphicTypeMapper
differently would be appreciated.
The second is why the first and second are the same (is it because the Object mapper has a cache (ouch!)?).
[EDIT: I should have mentioned that the use case for this is as a JSON provider for Jersey. I have a way of generating and configuring an ObjectMapper
at launch time, but the (in)ability to configure per-write is just for the test code above.]
private PolymorphicTypeValidator getPTV() {
return BasicPolymorphicTypeValidator.builder()
.denyForExactBaseType(Date.class)
.build();
}
@Test
public void serializationTest() {
try {
Date now = new Date();
// Create an object mapper and serialize the date
ObjectMapper om = new ObjectMapper();
String serialized1 = om.writeValueAsString(now); // result: 1605744866827
om.activateDefaultTypingAsProperty(getPTV(), ObjectMapper.DefaultTyping.EVERYTHING, "@class");
String serialized2 = om.writeValueAsString(now); // result: 1605744866827
ObjectMapper om2 = new ObjectMapper();
om2.activateDefaultTypingAsProperty(getPTV(), ObjectMapper.DefaultTyping.EVERYTHING, "@class");
String serialized3 = om2.writeValueAsString(now); // result: ["java.util.Date",1605744866827]
Logger.getLogger(SerializationTest.class).info(serialized1);
Logger.getLogger(SerializationTest.class).info(serialized2);
Logger.getLogger(SerializationTest.class).info(serialized3);
Assert.assertEquals("Unexpected change in serialization 1-2", serialized1, serialized2);
Assert.assertEquals("Unexpected change in serialization 1-3", serialized1, serialized3);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
Here's the output:
INFO 2020-11-18 16:14:27,065 [main] <> test.SerializationTest : 1605744866827
INFO 2020-11-18 16:14:27,066 [main] <> test.SerializationTest : 1605744866827
INFO 2020-11-18 16:14:27,066 [main] <> test.SerializationTest : ["java.util.Date",1605744866827]
org.junit.ComparisonFailure: Unexpected change in serialization 1-3
Expected :1605744866827
Actual :["java.util.Date",1605744866827]
回答1:
Read the documentation, i.e. the javadoc of ObjectMapper, which says (bold highlights by me):
Mapper instances are fully thread-safe provided that ALL configuration of the instance occurs before ANY read or write calls. If configuration of a mapper is modified after first usage, changes may or may not take effect, and configuration calls themselves may fail. If you need to use different configuration, you have two main possibilities:
Construct and use
ObjectReader
for reading,ObjectWriter
for writing. Both types are fully immutable and you can freely create new instances with different configuration using either factory methods ofObjectMapper
, or readers/writers themselves. Construction of newObjectReader
s andObjectWriter
s is a very light-weight operation so it is usually appropriate to create these on per-call basis, as needed, for configuring things like optional indentation of JSON.If the specific kind of configurability is not available via
ObjectReader
andObjectWriter
, you may need to use multipleObjectMapper
instead (for example: you can not change mix-in annotations on-the-fly; or, set of custom (de)serializers). To help with this usage, you may want to use methodcopy()
which creates a clone of the mapper with specific configuration, and allows configuration of the copied instance before it gets used. Note thatcopy()
operation is as expensive as constructing a newObjectMapper
instance: if possible, you should still pool and reuse mappers if you intend to use them for multiple operations.
来源:https://stackoverflow.com/questions/64903587/unexpected-serialization-behavior-with-configured-jackson-objectmapper