Support conditional type ID inclusion during deserialization

Open
#6,147 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
48/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Quiet
Tech stack
java

Research direction

Start with AsPropertyTypeDeserializer, especially _deserializeTypedForId and the referenced lines 131-143, then review JsonTypeInfo.visible and the public AsPropertyTypeDeserializer or StdTypeResolverBuilder APIs. Reproduce the supplied performance test and verify that default implementations can receive the type while non-default deserializers avoid the unnecessary intermediate allocations.

Written by the indexing model from the issue text.

Description

to-evaluate
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);
        }
    }
Image
Additional context

No response

Dominant language
Java
Stars
3.8k
Forks
1.6k
Avg merge
1d 18h
Merged PRs (30d)
59

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from FasterXML/jackson-databind

All issues in FasterXML/jackson-databind

Similar issues

More Java issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.