Let's say there is an existing abstract subclass that I want Jackson to always deserialize as a certain other class, but I didn't create the parent class so I can't add an annotation to the parent class. For example let's say that the requested type is java.lang.Number, but I always want Jackson to deserialize the value as a java.math.BigDecimal.
My actual use case involves an interface I always want to have deserialized as a concrete class I have created. If there is a com.example.thirdparty.Person interface someone has created, when some deserialization scenario arises for Person I want Jackson to deserialize to a com.example.mycustom.Neighbor record that I have created which implements Person.
I am using a Jackson JsonMapper.Builder to create an ObjectMapper. How can I tell the JsonMapper.Builder to do the following?
java.lang.Number is requested, deserialize the value as if java.math.BigDecimal were requested."com.example.thirdparty.Person is requested, deserialize the value as if com.example.mycustom.Neighbor were requested."I assume what I want is similar to the effects of @JsonDeserialize(as=ValueImpl.class), but I want to configure this on an ObjectMapper level using JsonMapper.Builder for java.lang.Number and com.example.thirdparty.Person regardless of the context; i.e. regardless of which classes have those types as fields. (In my use case these requested types won't even be fields anyway, but that's another story.)
AbstractTypeResolverYou can use AbstractTypeResolver to add rules on what desired class to instantiate on deserialization.
Let's set a rule to always deserialize Number as BigDecimal. You can create the ObjectMapper like this:
var builder = JsonMapper.builder();
var resolver = new SimpleAbstractTypeResolver();
resolver.addMapping(Number.class, BigDecimal.class);
resolver.addMapping(...);
resolver.addMapping(...);
var module = new SimpleModule();
module.setAbstractTypes(resolver);
builder.addModule(module);
return builder.build();
Module onlyIf you don't have a need to add an additional layer of abstraction, simply add type mapping on the Module itself the following way:
var builder = JsonMapper.builder();
var module = new SimpleModule();
module.addAbstractTypeMapping(Number.class, BigDecimal.class);
builder.addModule(module);
return builder.build();
@Test
void shouldDeserializeAsBigInteger() throws JsonProcessingException {
Integer a = 2;
var serialized = objectMapper.writeValueAsString(a);
var deserialized = objectMapper.readValue(serialized, Number.class);
assertThat(deserialized).isInstanceOf(BigDecimal.class);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With