如何忽略Jackson JSON-to-Object映射中的枚举字段?

Saq*_*qib 16 java jackson

我有一个JSON对象,如:

{"name":"John", "grade":"A"}
Run Code Online (Sandbox Code Playgroud)

要么

{"name":"Mike", "grade":"B"}
Run Code Online (Sandbox Code Playgroud)

要么

{"name":"Simon", "grade":"C"}
Run Code Online (Sandbox Code Playgroud)

等等

我试图将上面的JSON映射到:

@JsonIgnoreProperties(ignoreUnknown = true)
public class Employee{
      @JsonIgnoreProperties(ignoreUnknown = true)
      public enum Grade{ A, B, C }
      Grade grade;
      String name;

  public Grade getGrade() {
    return grade;
  }

  public void setGrade(Grade grade) {
    this.grade = grade;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }
}
Run Code Online (Sandbox Code Playgroud)

上面的映射工作正常,但将来会有更多的"等级"类型,比如D,E等打破现有的映射并抛出以下异常

05-08 09:56:28.130: W/System.err(21309): org.codehaus.jackson.map.JsonMappingException: Can not construct instance of Employee from String value 'D': value not one of declared Enum instance names
Run Code Online (Sandbox Code Playgroud)

有没有办法在枚举类型中忽略未知字段?

谢谢

ste*_*try 21

我找到了一种方法,如下所示:

public static void main(String[] args) throws JsonParseException, JsonMappingException, UnsupportedEncodingException, IOException {
    String json = "{\"name\":\"John\", \"grade\":\"D\"}";

    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);
    Employee employee = mapper.readValue(new ByteArrayInputStream(json.getBytes("UTF-8")), Employee.class);

    System.out.println(employee.getGrade());
}
Run Code Online (Sandbox Code Playgroud)

这输出:

空值

其他课程:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class Employee {
    private String name;
    private Grade grade;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Grade getGrade() {
        return grade;
    }

    public void setGrade(Grade grade) {
        this.grade = grade;
    }
}



import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public enum Grade {A, B, C}
Run Code Online (Sandbox Code Playgroud)

我还没有想过用注释做到这一点的方法.

我希望这有帮助.

  • 从 Jackson 2.8 开始,还有 READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE,它允许您设置默认值而不是 null。https://fasterxml.github.io/jackson-databind/javadoc/2.8/com/fasterxml/jackson/databind/DeserializationFeature.html#READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE (2认同)

Mic*_*ber 20

我认为你应该为枚举定义外部反序列化器Grade.

我为枚举添加了额外的字段 - UNKNOWN:

enum Grade {
    A, B, C, UNKNOWN;

    public static Grade fromString(String value) {
        for (Grade grade : values()) {
            if (grade.name().equalsIgnoreCase(value)) {
                return grade;
            }
        }

        return UNKNOWN;
    }
}
class Employee {

    @JsonDeserialize(using = GradeDeserializer.class)
    private Grade grade;
    private String name;

    public Grade getGrade() {
        return grade;
    }

    public void setGrade(Grade grade) {
        this.grade = grade;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Employee [grade=" + grade + ", name=" + name + "]";
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,解析器看起来像这样:

class GradeDeserializer extends JsonDeserializer<Grade> {
    @Override
    public Grade deserialize(JsonParser parser, DeserializationContext context)
            throws IOException, JsonProcessingException {
        return Grade.fromString(parser.getValueAsString());
    }
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

public class JacksonProgram {

    public static void main(String[] args) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        JsonFactory jsonFactory = new JsonFactory();
        JsonParser parser = jsonFactory
                .createJsonParser("{\"name\":\"John\", \"grade\":\"D\"}");
        Employee employee = objectMapper.readValue(parser, Employee.class);
        System.out.println(employee);
    }

}
Run Code Online (Sandbox Code Playgroud)

输出:

Employee [grade=UNKNOWN, name=John]
Run Code Online (Sandbox Code Playgroud)

如果您不想添加其他字段,则会返回null例如.

  • UNKNOWN意味着此时不知道价值.null表示 - 未设置值.在某些情况下可能会造成混淆,并可能导致NPE.此外,如果枚举值包含方法,我们可以更优雅的方式实现特殊的空值处理.对我来说,使用READ_UNKNOWN_ENUM_VALUES_AS_NULL功能的解决方案也很好.也许,比我好... (3认同)

Bog*_*mac 7

@JsonCreator与相比,提供了更简洁的解决方案@JsonDeserialize

想法是用注释您的valueOf()替换项(safeValueOf()在此示例中称为),@JsonCreator然后Jackson将使用您的实现对字符串进行反序列化。

请注意,该实现位于枚举内部,您可以将其用作其他对象中的字段而无需更改。

下面的解决方案包含在单元测试中,因此您可以直接运行它。

import static junit.framework.TestCase.assertEquals;

import java.io.IOException;

import org.junit.Test;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.databind.ObjectMapper;

public class EmployeeGradeTest {

    public enum Grade {
        A, B, C, OTHER;

        @JsonCreator
        public static Grade safeValueOf(String string) {
            try {
                return Grade.valueOf(string);
            } catch (IllegalArgumentException e) {
                return OTHER;
            }
        }
    }

    @Test
    public void deserialize() throws IOException {
        assertEquals(Grade.A, new ObjectMapper().readValue("\"A\"", Grade.class));
    }

    @Test
    public void deserializeNewValue() throws IOException {
        assertEquals(Grade.OTHER, new ObjectMapper().readValue("\"D\"", Grade.class));
    }
}
Run Code Online (Sandbox Code Playgroud)


Jes*_*son 7

我正在使用 boot2 (尽管这也可以在 boot 1 中工作),但您可以在应用程序属性/yaml 中启用反序列化功能;

spring:
  jackson:
    deserialization:
      READ_UNKNOWN_ENUM_VALUES_AS_NULL: true
Run Code Online (Sandbox Code Playgroud)