【问题标题】:Deserialize complex JSON to Java, classes nested multiple levels deep将复杂的 JSON 反序列化为 Java,类嵌套多层
【发布时间】:2017-04-13 05:57:21
【问题描述】:

我正在尝试将 Cucumber 的 Json 输出转换为单个 Java 对象。这包含嵌套四层深的对象,我在反序列化它时遇到了麻烦。我目前正在使用杰克逊,但愿意接受建议。 这是我的 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(){}
}

为了澄清,here 是嵌套工作原理的类图。

这个解决方案给了我以下错误:

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

是否可以快速修复这种方法以使其发挥作用,还是我应该尝试完全不同的方法?

【问题讨论】:

  • 你试过添加getter和setter吗?这些字段不是公共的,因此对象不能被序列化到这些类中
  • 我以为只需要二传手?我确实有这些,只是为了使代码更具可读性,这里省略了。
  • @TurbutAlin 添加吸气剂没有任何效果,恐怕。
  • @KeizerHarm 在你的 Match 实体中你错过了 location 属性
  • 我通常为此使用 gson。如果您将变量命名为与 json 中的对象相同的名称,则无需注释(尽管杰克逊可能相同)。如果您定义嵌套类(同一个 .java 文件中的子类),您确实应该将它们设为静态,但这并不意味着所述嵌套类的实例必须是静态的。我不确定为什么甚至可以使用非静态嵌套(内部)类,但你可以,但这不是你想要的。

标签: java json jackson inner-classes json-deserialization


【解决方案1】:

好的,我花了一些时间调试并试图找出问题所在,最后发现很明显。

implements Serializable

这就是我添加到 MatchObject 并起作用的那一行。

当我们首先尝试反序列化某个对象时,我们必须使这些类实现接口 Serializable

【讨论】:

  • 这让我取得了一些实际进展,谢谢!但我现在有一个新错误:“java.lang.NoSuchMethodError: com.fasterxml.jackson.databind.JavaType.isReferenceType()Z”
  • @KeizerHarm 可能您忘记了您的 getter/setter 或者您尝试反序列化的类型错误,例如将“hi”存储到整数属性中
【解决方案2】:

我刚刚尝试了您的示例代码,但奇怪的是,它可以工作。

能否请您仔细检查您的导入,如果 JSON 按提供的方式输入,并且 getter、setter、构造函数确实存在?

【讨论】:

  • 使用包 com.fasterxml.jackson 不起作用
  • 应该用 this.var = var 和 all 来实现构造函数吗?我以为它们应该是空的。
  • 空的和设置器或完整的构造器(设置所有字段)
  • @TurbutAlin 我做到了,但因为我的声望不到 15 人,所以他们没有被显示出来。
  • 非常感谢您的帮助!我只是还不想“关闭”这个问题,因为我不确定新错误是否与旧错误有关。正如您所指定的,Jackson 版本是 2.6.3。
【解决方案3】:

你可以从这段代码中得到反序列化的想法,

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
        }

希望对你有帮助

【讨论】:

    猜你喜欢
    • 2018-03-20
    • 1970-01-01
    • 2018-10-25
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多