Skip to content

Builder Deserialization with JsonCreator Value vs Array #2486

@vjkoskela

Description

@vjkoskela

There seems to be a difference in behavior when deserializing JSON into an object via a Builder when that Builder has a @JsonCreator method on it when that method takes a primitive vs an array.

Consider a pojo class like this:

    private static final class TestBean {

        public int getI() {
            return _i;
        }

        private TestBean(final Builder builder) {
            _i = builder._i;
        }

        private final int _i;
    }

Then consider a Builder for the pojo that supports deserialization value from a value as well as an object (or via code calling setX):

    public static final class Builder  {

        public Builder() { }

        @JsonCreator
        public Builder(final Integer value) {
            _i = value;
        }

        public void setI(final Integer value) {
            _i = value;
        }

        private Integer _i;
    }

This combination can be deserialized from {"i":3} and from 3.

However, if we instead declare a @JsonCreator method that accepts a List<Object> then the deserialization is only supported from [3] and not from {"i":3}. For example, replacing the above @JsonCreator annotated constructor with:

        @JsonCreator
        public Builder(final List<Object> jsonArray) {
            setI((int) jsonArray.get(0));
        }

This appears to be because in BeanDeserializerBase.java#L222 the value of _vanillaProcessing is set based in part on the value of _nonStandardCreation which considers _valueInstantiator.canCreateUsingArrayDelegate() but does not consider instantiation from a primitive value to be "non standard creation".

I am not sure which is the desired behavior. That is, it is an over-sight that with a @JsonCreator accepting a value that the same pojo can be deserialized from an object OR whether the array case should also support deserialization from an object.

In the case that we don't want the flexibility - and it seems reasonable that if you declare a @JsonCreator that this how the object should be built from JSON - then fix would be to include canCreateFromXXX for the various primitive types in the computation of _nonStandardCreation; although I am unclear on what the broader implications of this migh be.

In the case that we want to allow creation of objects from both an alternate representation (e.g. array or primitive) as well as from an object representation then we need a more fine-grained check when delegating to the vanilla path. In particular, we should go down that path if there is non-standard only because of an array delegate (but it's an object representation in json). This will likely lead to evaluating the "vanilla-ness" of a particular deserialization based at deserialization time instead of upfront.

Jackson Version: 2.10.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions