Skip to content

Allow skipping @JsonUnwrapped values if no properties matched, DeserializationFeature.USE_NULL_FOR_EMPTY_UNWRAPPED enabled #1497

Description

@victornoel

(note: same/similar as #1709 )

Hi,

After discussing this matter on the mailing list, I was redirected to creating an issue to ease some use case of @JsonUnwrapped.

Basically, my objective is to avoid using mutable objects and exploit as much as possible constructors to construct objects.

Taking this example:

class Location {
    public final int latitude, longitude;

    public Location(int latitude, int longitude) { ... }
}

class Place {
    public final String name;
    @JsonUnwrapped public final Location location;

    @JsonCreator
    public Place(@JsonProperty("name") String name,
                 @JsonProperty("latitude") int latitude, 
                 @JsonProperty("longitude") int longitude) {
        this.name = name;
        this.location = new Location(latitude, longitude);
    }
}

Currently, deserializing a Place object fails because Jackson first builds the Place object (successfully, including the location with the correct values) and then tries to set the location field. The latter fails because the latitude and longitude properties were already used to construct the Place, and thus are not used to construct the Location.
At the end of the deserialization process, the location field is initialised with an object with null values for latitude and longitude!

I would expect Jackson not to try to set the location field after a Place object was successfully constructed since a constructor is expected to build fully constructed objects?

Apparently (according to the discussion on the mailing list), the following code should have worked:

class Location {
    public final int latitude, longitude;

    public Location(int latitude, int longitude) { ... }
}

class Place {
    public final String name;
    @JsonUnwrapped public final Location location;

    @JsonCreator
    public Place(@JsonProperty("name") String name) {
        this.name = name;
        this.location = null;
    }
}

I.e., the Place object is partially created, and then Jackson would set the location field.
In practice it didn't work, not sure why. But with respect to my proposed solution to the first problem of this issue, I'm not sure it is a so good idea that this second way of doing things work: for me a constructor is meant to fully build an object!

FYI, the only solution I found to work is to have a parameter-less constructor and let Jackson handle everything its way. I feel there is some use case where a constructor would really be needed, for example if the properties must be reworked a bit before being set to the object (keeping in mind I don't want to use setters :).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.1most-wantedTag to indicate that there is heavy user +1'ing action (5 or more)

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions