Is your feature request related to a problem? Please describe.
When a default implementation is used on a polymorphic @JsonTypeInfo the visible = true attribute needs to be set for that default implementation to know the missing type. However for the non-default cases usually the type is known ahead of time, and making the type property visible to the concrete deserializer adds significant allocation cost for the intermediate TokenBuffer.
Specifically, this code snippet allocates a token buffer (with a 16 element segment), the associated TokenBuffer$Parser, and JsonParserSequence.
Describe the solution you'd like
Ideally, adding a third option to the JsonTypeInfo.visible field that indicates "visible only to the default implementation", but this is likely fairly complicated due to the field currently being a boolean.
Alternatively, perhaps adding an optimized JsonParser subtype like PrependedTypeProperty(String typeField, String typeId, JsonParser delegate) that avoids the majority of the allocations.
Currently, we're using our own subtype of AsPropertyTypeDeserializer that overrides _deserializeTypedForId that overrides if (_typeIdVisible) { to instead check if (deserializer == _defaultImplDeserializer) { in a few targeted places we've observed this performance issue, but this is not ideal because those are internal APIs. If modifying @JsonTypeInfo is too high lift, perhaps adding the option to the public API of AsPropertyTypeDeserializer or StdTypeResolverBuilder would be an alternative.
Performance Test
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXISTING_PROPERTY,
property = "type",
visible = true,
defaultImpl = Default.class)
@JsonSubTypes(@JsonSubTypes.Type(value = Concrete.class, name = "concrete"))
private interface Base {}
private record Default(String type) implements Base {}
@JsonTypeName("concrete")
@JsonPropertyOrder({"type", "content"})
private static final class Concrete implements Base {
@JsonProperty("type")
public String type() {
return "concrete";
}
@JsonProperty("content")
public int content;
}
public static void main(String[] args) throws IOException {
ObjectMapper objectMapper =
new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Concrete obj = new Concrete();
obj.content = 12345;
byte[] bytes = objectMapper.writeValueAsBytes(
IntStream.range(0, 1000).mapToObj(_x -> obj).toList());
TypeReference<List<Base>> type = new TypeReference<>() {};
for (int i = 0; i < 10_000; i++) {
objectMapper.readValue(bytes, type);
}
}
Additional context
No response
Is your feature request related to a problem? Please describe.
When a default implementation is used on a polymorphic
@JsonTypeInfothevisible = trueattribute needs to be set for that default implementation to know the missing type. However for the non-default cases usually the type is known ahead of time, and making thetypeproperty visible to the concrete deserializer adds significant allocation cost for the intermediateTokenBuffer.Specifically, this code snippet allocates a token buffer (with a 16 element segment), the associated
TokenBuffer$Parser, andJsonParserSequence.Describe the solution you'd like
Ideally, adding a third option to the
JsonTypeInfo.visiblefield that indicates "visible only to the default implementation", but this is likely fairly complicated due to the field currently being a boolean.Alternatively, perhaps adding an optimized
JsonParsersubtype likePrependedTypeProperty(String typeField, String typeId, JsonParser delegate)that avoids the majority of the allocations.Currently, we're using our own subtype of
AsPropertyTypeDeserializerthat overrides_deserializeTypedForIdthat overridesif (_typeIdVisible) {to instead checkif (deserializer == _defaultImplDeserializer) {in a few targeted places we've observed this performance issue, but this is not ideal because those are internal APIs. If modifying@JsonTypeInfois too high lift, perhaps adding the option to the public API ofAsPropertyTypeDeserializerorStdTypeResolverBuilderwould be an alternative.Performance Test
Additional context
No response