问题
Stumbled on this behavior when making some experiments with ObjectMapper
. See Junit5 test cases below and what those print for me in comments.
class TestIt {
private ObjectMapper om = new ObjectMapper();
private TestClass testClass = new TestClass();
@Getter @Setter
public class TestClass {
private final String value = LocalDate.now().toString();
private String valueLeftNull;
}
@Test
void defaultMapping() throws JsonProcessingException {
System.out.println(om.writeValueAsString(testClass));
// {"value":"2020-11-02","valueLeftNull":null}
}
@Test
void nonNull() throws JsonProcessingException {
om.setSerializationInclusion(Include.NON_NULL);
System.out.println(om.writeValueAsString(testClass));
// {"value":"2020-11-02"}
}
@Test
void both() throws JsonProcessingException {
System.out.println(om.writeValueAsString(testClass));
om.setSerializationInclusion(Include.NON_NULL);
System.out.println(om.writeValueAsString(testClass));
System.out.println(om.writeValueAsString(new TestClass()));
// {"value":"2020-11-02","valueLeftNull":null}
// {"value":"2020-11-02","valueLeftNull":null}
// {"value":"2020-11-02","valueLeftNull":null}
}
}
The last one both()
is what I am wondering. Is it normal functionality that ObjectMapper
ignores the inclusion instruction after the first serialization?
回答1:
By default Jackson
creates BeanSerializer instance for each POJO
class. It is created on demand when is needed and cached. So it's configuration depends from current state of ObjectMapper
and if you change ObjectMapper
you need to clear cache:
((DefaultSerializerProvider) om.getSerializerProvider()).flushCachedSerializers();
to force ObjectMapper
to create new instance of BeanSerializer
.
Take a look at documentation for BeanSerializerFactory:
...
Finally, since all caching is handled by the serializer provider (not factory) and there is no configurability, this factory is stateless. This means that a global singleton instance can be used.
and cachedSerializersCount method:
Method that can be used to determine how many serializers this provider is caching currently (if it does caching: default implementation does) Exact count depends on what kind of serializers get cached; default implementation caches all serializers, including ones that are eagerly constructed (for optimal access speed)
Probably the best solution would be to create two instances of ObjectMapper
:
class TestIt {
private JsonMapper nonNullMapper = JsonMapper.builder()
.serializationInclusion(JsonInclude.Include.NON_NULL)
.build();
private JsonMapper defaultMapper = JsonMapper.builder().build();
private TestClass testClass = new TestClass();
@Getter
@Setter
public static class TestClass {
private final String value = LocalDate.now().toString();
private String valueLeftNull;
}
void defaultMapping() throws JsonProcessingException {
System.out.println(defaultMapper.writeValueAsString(testClass));
}
void nonNull() throws JsonProcessingException {
System.out.println(nonNullMapper.writeValueAsString(testClass));
}
void both() throws JsonProcessingException {
System.out.println(defaultMapper.writeValueAsString(testClass));
System.out.println(nonNullMapper.writeValueAsString(testClass));
System.out.println(nonNullMapper.writeValueAsString(new TestClass()));
}
}
来源:https://stackoverflow.com/questions/64642641/configuring-objecmapper-null-serialization-after-first-serialization-does-not-ha