Jackson JSON 在反序列化集合时窒息
Jackson JSON chokes when deserializing a Collection
Java 11,Spring Boot 2.5 和 Jackson 2.12 在这里。我有以下 Java 类:
// using lombok annos to generate getters & setters
@Data
public class ExamUnit implements Comparable<ExamUnit> {
private Long id;
private String name;
private String displayName;
private Long order;
private Exam exam;
// compareTo, equals & hashCode are necessary so that the TreeSet below sorts ExamUnits
// correctly, according to my needs
@Override
public int compareTo(ExamUnit other) {
if (this.equals(other)) {
return 0;
} else if (this.order < other.order) {
return 1;
}
return 0;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ExamUnit examUnit = (ExamUnit) o;
return Objects.equals(name, examUnit.name) &&
Objects.equals(displayName, examUnit.displayName) &&
Objects.equals(order, examUnit.order);
}
@Override
public int hashCode() {
return Objects.hash(name, displayName, order);
}
}
和:
@Data
public class Exam {
private Long id;
private String name;
private String displayName;
private SortedSet<ExamUnit> units = new TreeSet<>();
}
那我有一个“考试” JSON string:
{
"id": 1,
"name": "science",
"displayName": "Science Exam",
"units": [
{
"id": 1,
"name": "chemistry",
"displayName": "Chemistry Unit",
"order": 1
},
{
"id": 2,
"name": "biology",
"displayName": "Biology Unit",
"order": 2
}
]
}
这是有效的JSON,您可以自己验证。它似乎确实遵循 Java 类型的模型。
然后我有一些代码来读取字符串并将其反序列化:
@Test
public void deserializeExamJson() {
String examJson = "{\n" +
" \"id\": 1,\n" +
" \"name\": \"science\",\n" +
" \"displayName\": \"Science Exam\",\n" +
" \"units\": [\n" +
" {\n" +
" \"id\": 1,\n" +
" \"name\": \"chemistry\",\n" +
" \"displayName\": \"Chemistry Unit\",\n" +
" \"order\": 1\n" +
" },\n" +
" {\n" +
" \"id\": 2,\n" +
" \"name\": \"biology\",\n" +
" \"displayName\": \"Biology Unit\",\n" +
" \"order\": 2\n" +
" }\n" +
" ]\n" +
"}";
Exam exam = null;
try {
exam = objectMapper.readValue(examJson, Exam.class);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
assertThat(exam.getName()).isEqualTo("science");
}
当这个测试运行时,它失败了:
java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (START_OBJECT), expected VALUE_STRING: need JSON String that contains type id (for subtype of java.util.SortedSet)
at [Source: (StringReader); line: 6, column: 5] (through reference chain: com.me.myapp.Exam["units"])
在你的 ExamUnit class 中用 @JsonIgnore
注释你的 属性 private Exam exam;
Java 11,Spring Boot 2.5 和 Jackson 2.12 在这里。我有以下 Java 类:
// using lombok annos to generate getters & setters
@Data
public class ExamUnit implements Comparable<ExamUnit> {
private Long id;
private String name;
private String displayName;
private Long order;
private Exam exam;
// compareTo, equals & hashCode are necessary so that the TreeSet below sorts ExamUnits
// correctly, according to my needs
@Override
public int compareTo(ExamUnit other) {
if (this.equals(other)) {
return 0;
} else if (this.order < other.order) {
return 1;
}
return 0;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ExamUnit examUnit = (ExamUnit) o;
return Objects.equals(name, examUnit.name) &&
Objects.equals(displayName, examUnit.displayName) &&
Objects.equals(order, examUnit.order);
}
@Override
public int hashCode() {
return Objects.hash(name, displayName, order);
}
}
和:
@Data
public class Exam {
private Long id;
private String name;
private String displayName;
private SortedSet<ExamUnit> units = new TreeSet<>();
}
那我有一个“考试” JSON string:
{
"id": 1,
"name": "science",
"displayName": "Science Exam",
"units": [
{
"id": 1,
"name": "chemistry",
"displayName": "Chemistry Unit",
"order": 1
},
{
"id": 2,
"name": "biology",
"displayName": "Biology Unit",
"order": 2
}
]
}
这是有效的JSON,您可以自己验证。它似乎确实遵循 Java 类型的模型。
然后我有一些代码来读取字符串并将其反序列化:
@Test
public void deserializeExamJson() {
String examJson = "{\n" +
" \"id\": 1,\n" +
" \"name\": \"science\",\n" +
" \"displayName\": \"Science Exam\",\n" +
" \"units\": [\n" +
" {\n" +
" \"id\": 1,\n" +
" \"name\": \"chemistry\",\n" +
" \"displayName\": \"Chemistry Unit\",\n" +
" \"order\": 1\n" +
" },\n" +
" {\n" +
" \"id\": 2,\n" +
" \"name\": \"biology\",\n" +
" \"displayName\": \"Biology Unit\",\n" +
" \"order\": 2\n" +
" }\n" +
" ]\n" +
"}";
Exam exam = null;
try {
exam = objectMapper.readValue(examJson, Exam.class);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
assertThat(exam.getName()).isEqualTo("science");
}
当这个测试运行时,它失败了:
java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (START_OBJECT), expected VALUE_STRING: need JSON String that contains type id (for subtype of java.util.SortedSet)
at [Source: (StringReader); line: 6, column: 5] (through reference chain: com.me.myapp.Exam["units"])
在你的 ExamUnit class 中用 @JsonIgnore
private Exam exam;