В fastxml, после десериализации json, если enum является первым свойством в классе, другие поля являются пустыми - PullRequest
0 голосов
/ 18 ноября 2018

В fastxml, после десериализации json, если enum (с JsonFormat.Shape.OBJECT) является первым свойством в классе, другие поля имеют значение null.

Почему перечисление должно быть последним объявленным свойством в классе для десериализации других полейправильно?

Может быть, это может быть ошибка в 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;
}
} 

Пример enum 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"
  }
}

1 Ответ

0 голосов
/ 18 ноября 2018

Я не могу сказать вам, если это ошибка, вы можете отладить и пройтись по коду, чтобы понять, как Джексон "терпит неудачу" в этом сценарии.Использование FAIL_ON_UNKNOWN_PROPERTIES скрывает проблему, которая использует String в качестве типа параметра фабричного метода forValue.Короче говоря, Джексон "застревает" при обходе токенов содержимого JSON.

Чтобы исправить это должным образом, т.е.не полагайтесь на порядок, у вас есть несколько вариантов.Во-первых, избавьтесь от формы JsonFormat.Shape.OBJECT для сериализации типа enum и соответствующего ему @JsonCreator.Сериализация / десериализация по умолчанию для перечисления состоит в том, чтобы использовать его имя в любом случае.

Во-вторых, если вы действительно хотите сохранить форму OBJECT, вам нужно изменить свой метод @JsonCreator, чтобы получить ObjectNode, поскольку это то, что содержит JSON, а не String.Оттуда вы можете выполнить десериализацию самостоятельно (при условии, что у вас больше констант enum)

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