question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Deserialize missing value of `EXTERNAL_PROPERTY` type using custom `NullValueProvider`

See original GitHub issue

Is your feature request related to a problem? Please describe. I am currently trying to deserialize a structure with a generic field that has an external type property, where the type property is always present, but the actual property may be absent, in which case it should just use a custom NullValueProvider.

The json can either look like this:

{
  "type": "inner-implementation",
  "value": {
    "foo": "bar"
  }
}

Or like this, in which case value should use the NullValueProvider:

{
  "type": "inner-implementation"
}

The outer type looks like this:

public class Wrapper<I extends Inner> {
    @JsonTypeInfo(use = Id.NAME, include = As.EXTERNAL_PROPERTY)
    private I value;

    public Wrapper(@JsonProperty(value = "value", required = true) I value) {
        this.value = value;
    }
}

And the inner types all implement this interface:


@JsonSubTypes({
        @Type(InnerImplementation.class),
})
public interface Inner {}

With an implementation of the inner type looking like this:


@JsonTypeName("inner-implementation")
@JsonDeserialize(using = InnerImplementationDeserializer.class)
public class InnerImplementation implements Inner {
    @Nullable
    private String foo;

    public InnerImplementation(@Nullable String foo) {
        this.foo = foo;
    }
}

Each implementation of Inner also has a deserializer which implements the getNullValue method:

class InnerImplementationDeserializer extends StdNodeBasedDeserializer<InnerImplementation> {
    protected InnerImplementationDeserializer() {
        super(TypeFactory.defaultInstance().constructType(InnerImplementation.class));
    }

    @Override
    public InnerImplementation convert(JsonNode root, DeserializationContext ctxt) throws IOException {
        JsonNode foo = root.get("foo");

        return new InnerImplementation(foo != null ? foo.textValue() : null);
    }

    @Override
    public InnerImplementation getNullValue(DeserializationContext ctxt) throws JsonMappingException {
        return new InnerImplementation(null);
    }
}

I have also disabled FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY.

The first snippet deserializes without problems, and when I remove required = true from the value property, the second snippet deserializes with Wrapper#value being null. With required = true however, a com.fasterxml.jackson.databind.exc.MismatchedInputException is thrown.

The exception originates from this part of the jackson databind codebase.

Describe the solution you’d like In the linked snippet of jackson code, it would in my opinion be appropriate to use the custom NullValueProviders if FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY is disabled.

Usage example The feature would work like shown above, however depending on how reasonable this approach generally is, the option FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY could be disabled by default.

Additional context The underlying WRAPPER_ARRAY property used in the background by EXTERNAL_PROPERTY was already changed to support this behaviour: https://github.com/fasterxml/jackson-databind/issues/2467

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:6 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
fxshleincommented, Jul 5, 2022

Fix could be simple, or very difficult, it unfortunately depends on how current handling is implemented.

Given that the ExternalTypeHandler just “fakes” an array structure, and the deserializer for EXTERNAL_PROPERTY then just extends the one for WRAPPER_ARRAY and inherits all its behavior, including https://github.com/FasterXML/jackson-databind/issues/2467 (which is basically the same issue as this one, just for arrays), this is already supported by the deserializer. In the absent case, the ExternalTypeHandler just needs to not write the second field of the array, like I already tested here: https://github.com/fxshlein/jackson-databind/commit/a965ec73bc15302aad9d4edbe7bdcc784c5675a2

0reactions
cowtowncodercommented, Aug 3, 2022

Merged, will be in 2.14.0.

Read more comments on GitHub >

github_iconTop Results From Across the Web

JsonDeserializer (jackson-databind 2.13.0 API) - FasterXML
Method called to determine value to be used for "empty" values (most commonly when deserializing from empty JSON Strings). Usually this is same...
Read more >
Ignore missing properties during Jackson JSON ...
I ran across this when trying to deserialize JSON numbers to Kotlin data classes (with constructor properties), and only found stackoverflow.com/questions/ ...
Read more >
JSON Class | Apex Reference Guide - Salesforce Developers
Contains methods for serializing Apex objects into JSON format and deserializing JSON content that was serialized using the serialize method in this class....
Read more >
Inheritance in Jackson | Baeldung
This tutorial will demonstrate how to handle inclusion of subtype metadata and ignoring properties inherited from superclasses with Jackson.
Read more >
How to serialize properties of derived classes with System ...
For polymorphic serialization to work, the type of the serialized value should be that of the polymorphic base type. This includes using the ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found