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.)
AbstractTypeResolver
You 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);
}