首页 > 解决方案 > fastxml中,反序列化json后,如果枚举是类中的第一个属性,其他字段为null

问题描述

在fastxml中,反序列化json后,如果枚举(带有JsonFormat.Shape.OBJECT)是类中的第一个属性,其他字段为空。

为什么枚举应该是类中最后声明的属性以正确反序列化其他字段?

也许这可能是fastxml中的一个错误?

示例类MyClass

public class MyClass {

// >>>
// >>> element field is null after deserialization
// >>>
private MyEnum option; // first
private String element; // --> null

// >>> 
// >>> correctly deserialized if enum is last in order
// >>>
// private String element; // --> "elem"
// private MyEnum option; // last


public MyEnum getOption() {
    return option;
}

public void setOption(MyEnum option) {
    this.option = option;
}

public String getElement() {
    return element;
}

public void setElement(String element) {
    this.element = element;
}
} 

示例枚举MyEnum

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum MyEnum {

FIRST;

@JsonProperty
public String getOption() {
    return name();
}

@JsonCreator
public static MyEnum forValue(String option) {
    return FIRST;
}
}

示例主测试类Main

    public class Main {
public static void main(String[] args) throws IOException {
    ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

    MyClass myClass = new MyClass();

    myClass.setElement("elem");
    myClass.setOption(MyEnum.FIRST);

    String serialized = mapper.writer().withDefaultPrettyPrinter().writeValueAsString(myClass);
    System.out.println(String.format("serialized - %s", serialized));

    MyClass deserialized = mapper.readValue(serialized, MyClass.class);

    String deserializedResult = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(deserialized);
    System.out.println(String.format("deserialized - %s", deserializedResult));
}
}

输出显示字段是null在反序列化之后:

serialized - {
  "option" : {
   "option" : "FIRST"
  },
  "element" : "elem"
}
deserialized - {
  "option" : {
    "option" : "FIRST"
  },
  "element" : null
}

固定顺序后的输出(中未注释的行MyClass):

serialized - {
  "element" : "elem",
  "option" : {
    "option" : "FIRST"
  }
}
deserialized - {
  "element" : "elem",
  "option" : {
    "option" : "FIRST"
  }
}

标签: javaenumsjacksondeserializationfasterxml

解决方案


我无法告诉您这是否是错误,您可以调试并逐步执行代码以了解杰克逊在这种情况下如何“失败”。您的使用FAIL_ON_UNKNOWN_PROPERTIES隐藏了问题,该问题用作工厂方法String的参数类型。forValue简而言之,Jackson 在遍历 JSON 内容的标记时“卡住”了。

正确修复它,即。不依赖订单,你有几个选择。首先,去掉JsonFormat.Shape.OBJECT序列化枚举类型及其对应的形状@JsonCreator。枚举的默认序列化/反序列化是无论如何都使用它的名称。

其次,如果你真的想保持 OBJECT 形状,你需要改变你的@JsonCreator方法来接收一个ObjectNode,因为那是 JSON 包含的,而不是一个String. 从那里,您可以自己执行反序列化(假设您有更多枚举常量)

@JsonCreator
public static MyEnum forValue(ObjectNode object) {
    return MyEnum.valueOf(object.get("option").asText());
}

推荐阅读