Определить тип объекта во время десериализации на основе свойств документа XML в Джексоне - нет JsonNode - PullRequest
0 голосов
/ 11 февраля 2019

У меня есть документ XML, который я хочу десериализовать в объект класса, который я не знаю во время компиляции, и тип определяется как именем корневого элемента документа, так и текстовым содержимым элемента type,Проблема двоякая:

  1. У меня есть списки элементов в моем документе XML, поэтому я не могу разобрать его в JsonNode / Map, потому что в лучшем случае это будеттолько предоставьте мне последнее значение в списке, информация теряется в процессе.Все решения, которые я нашел, основаны на JsonNode API (например, convertValue или treeToValue).

  2. Я не могу использовать JsonTypeInfo - я не знаюконкретные классы, которые будут deserialised, и поэтому я не могу использовать аннотации.Кроме того, я не думаю, что JsonTypeInfo является настолько гибким, чтобы включать как имя корневого элемента, так и значение свойства.

Я попытался использовать пользовательский десериализатор, который обернул бы фактический проанализированный JsonNode в другой Object с rootElement в качестве единственного ключа (по умолчанию этот корневой элемент не включен в анализируемый документ).После этого я десериализирую документ, получаю корневой элемент из узла, затем беру значение элемента типа, объединяю их, создаю имя класса и затем преобразовываю JsonNode в конечный объект.Проблема с этим подходом состоит в том, что он плохо обрабатывает списки и либо выдает и исключает недопустимое отображение, либо предоставляет мне последний элемент списка в зависимости от того, как я пишу свою модель или настраиваю маппер.package zm.study.xmlserialize.jackson;

import static org.junit.Assert.assertEquals;

import java.io.StringReader;
import java.util.List;

import org.junit.Test;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.deser.FromXmlParser;

public class JacksonListTest2 {
 public static class A < D extends AData > {
  public String type;
  public D data;
 }

 public static class AData {}

 public static class BRequestData extends AData {
  @JacksonXmlElementWrapper(useWrapping = false)
  public List < String > bs;
 }

 public static class BRequest extends A {}

 @Test
 public void test() throws Exception {
  String xml;

  xml = "<Request><type>B</type><data><bs>1</bs><bs>2</bs></data></Request>";

  XmlMapper mapper = new XmlMapper();

  mapper.registerModule(
   new SimpleModule()
   .addDeserializer(JsonNode.class, new JsonNodeDeserializer() {
    @Override
    public JsonNode deserialize(JsonParser p, DeserializationContext ctxt) throws java.io.IOException {
     String rootName = ((FromXmlParser) p).getStaxReader().getLocalName();
     return ctxt.getNodeFactory().objectNode().set(rootName, super.deserialize(p, ctxt));
    };
   })
  );

  JsonNode rootNode = mapper.readTree(new StringReader(xml));
  String rootName = rootNode.fields().next().getKey();
  JsonNode contentNode = rootNode.get(rootName);
  String type = contentNode.get("type").asText();
  String className = getClass().getCanonicalName() + "$" + type + rootName;

  BRequest value = (BRequest) mapper.convertValue(contentNode, Class.forName(className));
  System.out.println(value.data.bs);
  assertEquals(2, value.data.bs.size());
 }

}

Мой подход приводит к исключению:

Невозможно десериализовать экземпляр java.util.ArrayList из токена VALUE_STRING

Я также попытался создать пользовательский десериализатор, разбирающий достаточно документа, чтобы выяснить, с каким типом я имею дело, и затем делегировать оставшуюся часть фактического анализа (элемент данных) десериализатору по умолчанию, но мне не удалосьнаписать какой-нибудь разумный код, чтобы сделать это.

Я думаю, мне нужен новый подход, есть идеи?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...