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

我有一个JSON对象,如:

{"name":"John", "grade":"A"} 

要么

 {"name":"Mike", "grade":"B"} 

要么

 {"name":"Simon", "grade":"C"} 

等等

我试图将上面的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; } } 

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

 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 

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

谢谢

我认为你应该为Grade enum定义外部反序列化器 。

我为枚举添加了额外的字段 – 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 + "]"; } } 

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

 class GradeDeserializer extends JsonDeserializer { @Override public Grade deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException { return Grade.fromString(parser.getValueAsString()); } } 

用法示例:

 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); } } 

输出:

 Employee [grade=UNKNOWN, name=John] 

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

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

 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()); } 

这输出:

空值

其他课程:

 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} 

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

我希望这有帮助。

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

我们的想法是使用safeValueOf()注释你的valueOf()替换(在这个例子中称为safeValueOf() )然后Jackson将使用你的实现反序列化字符串。

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

下面的解决方案包含在unit testing中,因此您可以直接运行它。

 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)); } }