使用Map数据类型反序列化Java中的复杂Json

问题描述

我有以下通过HTTP请求解析的JSON对象。

{
 "firstName": "User","lastName": "Test","emailId": "testnew@gmail.com","formsAndQuestions": {
   "Form1": {
      "Question1": {
        "value": "NEVER","isBoolean": false
      },"Question2": {
        "value": "YES"
      }
    },"Form2": {
      "Question1": {
        "value": "OTHER"
      }
    }
  }
}

表单对象可以是动态的。因此,我正在使用以下变量在Java类中对此序列化。

Map<String,Map<String,String>>> forms;

然后,我将通过下面的复杂循环来迭代它们并读取答案值。

for (Map.Entry<String,String>>> entry : input.formsAndQuestions().get().entrySet()) {
        logger.log("Form: " + entry.getKey());
        for (Map.Entry<String,String>> entry1 : entry.getValue().entrySet()) {
            logger.log("Question: " + entry1.getKey());
            for (Map.Entry<String,String> entry2 : entry1.getValue().entrySet()) {
                logger.log("key: " + entry2.getKey());
                logger.log("value: " + entry2.getValue());
            }
        }
    }

有更好的方法吗?循环似乎很复杂。我不想创建用于反序列化json的Java对象类,因为“ formsAndQuestions”对象可以添加/删除多个表单,而每个表单都可以添加或删除多个问题/答案。

非常感谢您对此方法的反馈。

解决方法

即使形式和问题有所不同,结构也是相同的。您可以使用Java批注在@JsonAnySetter中轻松对此建模,以正确设置随机形式。看下面的例子:

import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

public class FormsAndQuestionsApp {
    public static void main(String[] args) throws IOException {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        ObjectMapper mapper = new ObjectMapper();

        Result result = mapper.readValue(jsonFile,Result.class);
        result.getFormsAndQuestions().getForms().forEach(System.out::println);
    }
}

@Data
@ToString
class Result {

    private String firstName;
    private String lastName;
    private String emailId;
    private FormsAndQuestions formsAndQuestions;
}

@Data
@ToString
class FormsAndQuestions {
    private List<Form> forms = new ArrayList<>();

    @JsonAnySetter
    public void anySetter(String formName,Map<String,Question> questions) {
        // update questions with keys (question's name)
        questions.forEach((k,v) -> v.setQuestion(k));

        forms.add(new Form(formName,questions.values()));
    }
}

@Data
@ToString
@AllArgsConstructor
class Form {

    private String name;
    private Collection<Question> questions;
}

@Data
@ToString
class Question {
    private String question;
    private String value;
    private Boolean isBoolean;
}

上面的代码打印:

Form(name=Form1,questions=[Question(question=Question1,value=NEVER,isBoolean=false),Question(question=Question2,value=YES,isBoolean=null)])
Form(name=Form2,value=OTHER,isBoolean=null)])

关键点是public void anySetter(String formName,Question> questions)方法。使用@JsonAnySetter会将JSON Object转换为列表,因为对于每个未知的key-value对,都会调用此方法。另外,我们将内部对象转换为适当的Question POJOvalue字段由Jackson设置,我们只需要设置question属性。现在,遍历此列表并稍后在某些业务逻辑中使用应该更容易。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...