Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing properties when deserializing using a builder class with a non-default constructor and a mutator annotated with @JsonUnwrapped #1573

Closed
senojj opened this issue Mar 24, 2017 · 0 comments
Milestone

Comments

@senojj
Copy link
Contributor

senojj commented Mar 24, 2017

When deserializing using a builder class with a non-default constructor and any number of mutator methods annotated with @JsonUnwrapped, the BuilderBasedDeserializer::deserializeUsingPropertyBasedWithUnwrapped method cuts short the process of adding SettableBeanProperties.

The logic dictates that once all properties necessary to construct the builder have been found, the builder is constructed using all known SettableBeanProperties that have been found up to that point in the tokenizing process.

Therefore, in the case that the builder has a single property required for construction, and that property is found anywhere other than at the end of the JSON content, any properties subsequent to the constructor property are not evaluated and are left with their default values.

Given the following classes:

@JsonDeserialize(builder = Employee.Builder.class)
public class Employee {
    private final long id;
    private final Name name;
    private final int age;

    private Employee(Builder builder) {
        id = builder.id;
        name = builder.name;
        age = builder.age;
    }

    public long getId() {
        return id;
    }

    public Name getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @JsonPOJOBuilder(withPrefix = "set")
    public static class Builder {
        private final long id;
        private Name name;
        private int age;

        @JsonCreator
        public Builder(@JsonProperty("emp_id") long id) {
            this.id = id;
        }

        @JsonUnwrapped
        public void setName(Name name) {
            this.name = name;
        }

        @JsonProperty("emp_age")
        public void setAge(int age) {
            this.age = age;
        }

        public Employee build() {
            return new Employee(this);
        }
    }
}

public class Name {
    private final String first;
    private final String last;

    @JsonCreator
    public Name(
        @JsonProperty("emp_first_name") String first,
        @JsonProperty("emp_last_name") String last
    ) {
        this.first = first;
        this.last = last;
    }

    public String getFirst() {
        return first;
    }

    public String getLast() {
        return last;
    }
}

And given the following JSON string:

{
    "emp_age": 30,
    "emp_id": 1234,
    "emp_first_name": "John",
    "emp_last_name": "Doe"
}

We will see the following output:

Employee emp = new ObjectMapper().readValue(json, Employee.class);

System.out.println(emp.getAge()); // 30
System.out.println(emp.getId()); // 1234
System.out.println(emp.getName()); // null

However, if we place the emp_id property at the end of the JSON string, we would get the following output:

Employee emp = new ObjectMapper().readValue(json, Employee.class);

System.out.println(emp.getAge()); // 30
System.out.println(emp.getId()); // 1234
System.out.println(emp.getName()); // Name Object

If we were to place emp_age and emp_first_name and emp_last_name all after the emp_id property in the JSON string, we would get the following output:

Employee emp = new ObjectMapper().readValue(json, Employee.class);

System.out.println(emp.getAge()); // 0
System.out.println(emp.getId()); // 1234
System.out.println(emp.getName()); // null
cowtowncoder added a commit that referenced this issue Mar 28, 2017
@cowtowncoder cowtowncoder added this to the 2.8 milestone Mar 28, 2017
@cowtowncoder cowtowncoder changed the title Bug: When deserializing using a builder class with a non-default constructor and a mutator annotated with @JsonUnwrapped When deserializing using a builder class with a non-default constructor and a mutator annotated with @JsonUnwrapped Mar 28, 2017
@cowtowncoder cowtowncoder changed the title When deserializing using a builder class with a non-default constructor and a mutator annotated with @JsonUnwrapped Missing properties when deserializing using a builder class with a non-default constructor and a mutator annotated with @JsonUnwrapped Mar 28, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants