Десериализовать сложный JSON на Java, классы вложенные несколько уровней глубоко

Я пытаюсь сделать вывод Json из Cucumber в один объект Java. Это содержит объекты, вложенные в четыре уровня, и у меня возникли проблемы с десериализацией. В настоящее время я использую Jackson, но открыт для предложений. Вот мой код Json:

{
"line": 1,
"elements": [
  {
    "line": 3,
    "name": "Converteren centimeters naar voeten/inches",
    "description": "",
    "id": "applicatie-neemt-maten-in-cm-en-converteert-ze-naar-voet/inch,-en-vice-versa;converteren-centimeters-naar-voeten/inches",
    "type": "scenario",
    "keyword": "Scenario",
    "steps": [
      {
        "result": {
          "duration": 476796588,
          "status": "passed"
        },
        "line": 4,
        "name": "maak Maten-object aan met invoer in "centimeters"",
        "match": {
          "arguments": [
            {
              "val": "centimeters",
              "offset": 37
            }
          ],
          "location": "StepDefinition.maakMatenObjectAanMetInvoerIn(String)"
        },
        "keyword": "Given "
      },
      {
        "result": {
          "duration": 36319,
          "status": "passed"
        },
        "line": 5,
        "name": "ik converteer",
        "match": {
          "location": "StepDefinition.converteerMaten()"
        },
        "keyword": "When "
      },
      {
        "result": {
          "duration": 49138,
          "status": "passed"
        },
        "line": 6,
        "name": "uitvoer bevat maat in "voeten/inches"",
        "match": {
          "arguments": [
            {
              "val": "voeten/inches",
              "offset": 23
            }
          ],
          "location": "StepDefinition.uitvoerBevatMaatIn(String)"
        },
        "keyword": "Then "
      }
    ]
  },
  {
    "line": 8,
    "name": "Converteren voeten/inches naar centimeters",
    "description": "",
    "id": "applicatie-neemt-maten-in-cm-en-converteert-ze-naar-voet/inch,-en-vice-versa;converteren-voeten/inches-naar-centimeters",
    "type": "scenario",
    "keyword": "Scenario",
    "steps": [
      {
        "result": {
          "duration": 84175,
          "status": "passed"
        },
        "line": 9,
        "name": "maak Maten-object aan met invoer in "voeten/inches"",
        "match": {
          "arguments": [
            {
              "val": "voeten/inches",
              "offset": 37
            }
          ],
          "location": "StepDefinition.maakMatenObjectAanMetInvoerIn(String)"
        },
        "keyword": "Given "
      },
      {
        "result": {
          "duration": 23928,
          "status": "passed"
        },
        "line": 10,
        "name": "ik converteer",
        "match": {
          "location": "StepDefinition.converteerMaten()"
        },
        "keyword": "When "
      },
      {
        "result": {
          "duration": 55547,
          "status": "passed"
        },
        "line": 11,
        "name": "uitvoer bevat maat in "centimeters"",
        "match": {
          "arguments": [
            {
              "val": "centimeters",
              "offset": 23
            }
          ],
          "location": "StepDefinition.uitvoerBevatMaatIn(String)"
        },
        "keyword": "Then "
      }
    ]
  }
],
"name": "Applicatie neemt maten in cm en converteert ze naar voet/inch, en vice versa",
"description": "",
"id": "applicatie-neemt-maten-in-cm-en-converteert-ze-naar-voet/inch,-en-vice-versa",
"keyword": "Feature",
"uri": "sample.feature"
}

Я пробовал несколько разных подходов. Сначала я использовал вложенные внутренние классы, но оказалось, что вы должны были сделать их статическими, что, как я боялся, не сработает, так как у меня есть несколько экземпляров одного и того же объекта внутри один (несколько "элементов" - объектов в корне, например). Затем я попытался поместить их в отдельные классы с аннотациями Json. Вот где это меня достало (опуская сеттеров):

public class CucumberUitvoer {
    private String name;
    private String description;
    private String id;
    private String keyword;
    private String uri;
    private int line;
    @JsonProperty("elements")
    private List<FeatureObject> elements;

    public CucumberUitvoer(){}
}

public class FeatureObject {
    private String name;
    private String description;
    private String id;
    private String type;
    private String keyword;
    private int line;
    @JsonProperty("steps")
    private List<StepObject> steps;

    public FeatureObject() {
    }
}

public class StepObject {
    @JsonProperty("result")
    private ResultObject result;
    private String name;
    private String given;
    private String location;
    private String keyword;
    private int line;
    @JsonProperty("match")
    private MatchObject match;

    public StepObject(){}
}

public class ResultObject {
    private int duration;
    private String status;

    public ResultObject(){}
}

public class MatchObject {
    @JsonProperty("arguments")
    private List<ArgumentObject> arguments;
    private String location;

    public MatchObject(){}
}

public class ArgumentObject {
    private String val;
    private String offset;

    public ArgumentObject(){}
}

разъяснить, здесьэто диаграмма классов того, как работает вложенность.

это решение дает мне следующую ошибку:

com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of nl.icaprojecten.TestIntegratieQuintor.JSONInterpreter.CucumberUitvoer out of START_ARRAY token

вот код, выполняющий фактическое отображение:

ObjectMapper mapper = new ObjectMapper();
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

    CucumberUitvoer obj1 = null;
    try {
        obj1 = mapper.readValue(json, CucumberUitvoer.class);
    } catch (IOException e) {
        e.printStackTrace();
    }

есть ли быстрое исправление этого подхода, чтобы сделать это работать или попробовать что-то совсем другое?

3 ответов


хорошо, я потратил некоторое время на отладку и пытался выяснить, в чем проблема, и, наконец, было что-то довольно очевидное.

implements Serializable

это строка, которую я добавил в MatchObject и работал.

когда мы пытаемся десериализовать какой-либо объект сначала, мы должны сделать эти классы реализующими интерфейс Serializable


Я просто попробовал ваш пример кода и как ни странно, это работает.

не могли бы вы дважды проверить свой импорт, если JSON приходит, как предусмотрено, и геттеры, сеттеры, конструкторы на самом деле есть?


вы можете получить идею из этого кода для десериализации,

public class testCustomDeSerializer extends JsonDeserializer<test> {

public testCustomDeSerializer() {
    this(null);
}

public TestCustomDeSerializer(Class t) {
   // super(t);
}

@Override
public Test deserialize(JsonParser p, DeserializationContext ctx) throws IOException, JsonProcessingException {
    ObjectCodec objectCodec = p.getCodec();
    JsonNode node = objectCodec.readTree(p);

    ObjectMapper objectMapper =  new ObjectMapper();
    Test test= new Test();


    test.setId(node.get("line").asText());

    List<elements> elementList = new ArrayList<>();
    JsonNode elementsNode = node.get("elements");
    Iterator<JsonNode> slaidsIterator = elementsNode.elements();
    while (slaidsIterator.hasNext()) {
        Steps steps= new Steps();
        JsonNode slaidNode = slaidsIterator.next();
        JsonNode stepNode= (JsonNode) slaidNode.get("Steps");
        BoundingPoly in = objectMapper.readValue(stepNode.toString(), Steps.class);
        elementsNode.setSteps(in);
        /// continue

 return
        }

надеюсь, что это помогает