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

Deserialization ignores other Object fields when Object or Array value used for enum #3369

Closed
Krishnaghimire opened this issue Jan 12, 2022 · 3 comments

Comments

@Krishnaghimire
Copy link

Krishnaghimire commented Jan 12, 2022

Describe the bug
Objectmapper deserialization ignore other field when Object or Array field used for enum

Version information
2.13.1

To Reproduce

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonIssue {
  public static void main(String[] args) throws JsonProcessingException {

    ObjectMapper objectMapper = new ObjectMapper();
    String validData = "{\"value\" : \"a\", \"person\" : \"Jeff\", \"age\" : 30}";

    Data data = objectMapper.readValue(validData, Data.class);
    System.out.println(data);

    String invalidEnum = "{\"value\" : \"e\", \"person\" : \"Jeff\", \"age\" : 30}";

    data = objectMapper.readValue(invalidEnum, Data.class);
    System.out.println(data);

    String enumAsArray = "{\"value\" : [\"a\"], \"person\" : \"Jeff\", \"age\" : 30}";

    data = objectMapper.readValue(enumAsArray, Data.class);
    System.out.println(data);

    String enumAsObjecty = "{\"value\" : {\"a\":{}}, \"person\" : \"Jeff\", \"age\": 30}";

    data = objectMapper.readValue(enumAsObjecty, Data.class);
    System.out.println(data);
  }

  @JsonIgnoreProperties(ignoreUnknown = true)
  static class Data {
    Enum value;
    String person;
    Integer age;

    public Enum getValue() {
      return this.value;
    }

    public String getPerson() {
      return this.person;
    }

    public Integer getAge() {
      return this.age;
    }

    public void setValue(Enum value) {
      this.value = value;
    }

    public void setPerson(String person) {
      this.person = person;
    }

    public void setAge(Integer age) {
      this.age = age;
    }

    public String toString() {
      return "JacksonIssue.Data(value=" + this.getValue() + ", person=" + this.getPerson() + ", age=" + this.getAge()
          + ")";
    }
  }

  enum Enum {
    A("ENUM_A"), B("ENUM_B"), C("ENUM_C"), D("ENUM_D");
    private String name;

    Enum(String name) {
      this.name = name;
    }

    @JsonCreator
    public static Enum fromName(String name) {
      if (name != null) {
        switch (name) {
          case "a":
            return A;
          case "b":
            return B;
          case "c":
            return C;
          case "d":
            return D;
        }
      }
      return null;
    }
  }
}

Expected behavior

3rd and 4th conversion should either fail or should de-serialize person and age.
Expected output:

JacksonIssue.Data(value=A, person=Jeff, age=30)
JacksonIssue.Data(value=null, person=Jeff, age=30)
JacksonIssue.Data(value=null, person=Jeff, age=30)
JacksonIssue.Data(value=null, person=Jeff, age=30)

Actual output:

JacksonIssue.Data(value=A, person=Jeff, age=30)
JacksonIssue.Data(value=null, person=Jeff, age=30)
JacksonIssue.Data(value=null, person=null, age=null)
JacksonIssue.Data(value=null, person=null, age=null)

Additional context
Its similar to #1859 one.
I could fix the issue by adding, p.skipChildren();
in FactoryBasedEnumDeserializer after line 151.
// 12-Oct-2021, tatu: We really should only get here if and when String
// value is expected; otherwise Deserializer should have been used earlier
value = p.getValueAsString();
p.skipChildren();

@Krishnaghimire Krishnaghimire added the to-evaluate Issue that has been received but not yet evaluated label Jan 12, 2022
@cowtowncoder cowtowncoder added 2.13 and removed to-evaluate Issue that has been received but not yet evaluated labels Jan 12, 2022
@cowtowncoder
Copy link
Member

cowtowncoder commented Jan 12, 2022

Part of the problem might be right here:

  @JsonIgnoreProperties(ignoreUnknown = true)

which you should first remove to see what is actually going on. It's bit of an anti-pattern for tests but very widely used.
Perhaps try things without it to see if there is another issue.

But I do agree that it looks like something odd might be happening.

@Krishnaghimire
Copy link
Author

It's same with/without JsonIgnoreProperties

@cowtowncoder
Copy link
Member

cowtowncoder commented Jan 15, 2022

Thank you for verifying. I am now looking into this issue.

And your analysis on skipChildren() is of course correct, apologies for missing it initially.

The main question really is whether to fail on non-scalar, or consider them same as Empty String.
Normally I would lean on exception but... in this case I think I'll go with Empty String.

@cowtowncoder cowtowncoder changed the title Objectmapper de-serialization ignore other field when Object or Array field used for enum Deserialization ignores other Object fields when Object or Array value used for enum Jan 15, 2022
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