使用地图数据类型反序列化 Java 中的复杂 Json
Deserializing a complex Json in Java with Map Data Type
我有以下 JSON 通过 HTTP 请求解析的对象。
{
"firstName": "User",
"lastName": "Test",
"emailId": "testnew@gmail.com",
"formsAndQuestions": {
"Form1": {
"Question1": {
"value": "NEVER",
"isBoolean": false
},
"Question2": {
"value": "YES"
}
},
"Form2": {
"Question1": {
"value": "OTHER"
}
}
}
}
表单对象可以是动态的。因此,我在 Java class 中使用以下变量对其进行反序列化。
Map<String, Map<String, Map<String, String>>> forms;
然后我将通过下面的复杂循环来迭代这些并读取答案值。
for (Map.Entry<String, Map<String, Map<String, String>>> entry : input.formsAndQuestions().get().entrySet()) {
logger.log("Form: " + entry.getKey());
for (Map.Entry<String, Map<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());
}
}
}
有更好的方法吗?循环看起来很复杂。我不想创建一个 Java 对象 class 来反序列化 json 因为“formsAndQuestions”对象可以有多种形式 added/removed 每个 questions/answers添加或删除表单。
非常感谢对此方法的任何反馈。
虽然形式和题型不同,但结构是一样的。您可以使用 @JsonAnySetter
注释在 Java
中轻松地对此进行建模,以设置适当的随机形式。看看下面的例子:
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, questions=[Question(question=Question1, value=OTHER, isBoolean=null)])
重点是public void anySetter(String formName, Map<String, Question> questions)
方法。使用 @JsonAnySetter
我们将 JSON Object
转换为列表,因为对于每个未知的 key-value
对都会调用此方法。此外,我们将内部对象转换为正确的 Question
POJO
。 value
字段由 Jackson
设置,我们只需要设置 question
属性。现在,遍历这个列表并在以后的一些业务逻辑中使用应该容易得多。
我有以下 JSON 通过 HTTP 请求解析的对象。
{
"firstName": "User",
"lastName": "Test",
"emailId": "testnew@gmail.com",
"formsAndQuestions": {
"Form1": {
"Question1": {
"value": "NEVER",
"isBoolean": false
},
"Question2": {
"value": "YES"
}
},
"Form2": {
"Question1": {
"value": "OTHER"
}
}
}
}
表单对象可以是动态的。因此,我在 Java class 中使用以下变量对其进行反序列化。
Map<String, Map<String, Map<String, String>>> forms;
然后我将通过下面的复杂循环来迭代这些并读取答案值。
for (Map.Entry<String, Map<String, Map<String, String>>> entry : input.formsAndQuestions().get().entrySet()) {
logger.log("Form: " + entry.getKey());
for (Map.Entry<String, Map<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());
}
}
}
有更好的方法吗?循环看起来很复杂。我不想创建一个 Java 对象 class 来反序列化 json 因为“formsAndQuestions”对象可以有多种形式 added/removed 每个 questions/answers添加或删除表单。
非常感谢对此方法的任何反馈。
虽然形式和题型不同,但结构是一样的。您可以使用 @JsonAnySetter
注释在 Java
中轻松地对此进行建模,以设置适当的随机形式。看看下面的例子:
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, questions=[Question(question=Question1, value=OTHER, isBoolean=null)])
重点是public void anySetter(String formName, Map<String, Question> questions)
方法。使用 @JsonAnySetter
我们将 JSON Object
转换为列表,因为对于每个未知的 key-value
对都会调用此方法。此外,我们将内部对象转换为正确的 Question
POJO
。 value
字段由 Jackson
设置,我们只需要设置 question
属性。现在,遍历这个列表并在以后的一些业务逻辑中使用应该容易得多。