Jackson 和 Iterable:如何反序列化
Jackson and Iterable: how to deserialize
我有一个 class Box
,它有一个 elements
类型的字段 Elements
实现了 Iterable
(见下面的代码)。后者包含一个 List
也称为 elements
如果我将 Elements
的字段 elements
设置为 private
,那么序列化会将其视为数组而不是 POJO
版本A完成序列化
{
"elements" : [ "a", "b", "c" ]
}
但是,我无法反序列化这个字符串。错误是:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `ser_deser_test.Elements` out of START_ARRAY token
at [Source: (String)"{
"elements" : [ "a", "b", "c" ]
}"; line: 2, column: 16] (through reference chain:
如果我将 elements
设置为 public
,那么 Box
的 elements
将被视为 POJO,我有这个有趣的两个级别其中有 elements
个。然而,反序列化在这种情况下有效。
按版本 B 序列化
{
"elements" : {
"elements" : [ "a", "b", "c" ]
}
}
我的问题是:我怎样才能让反序列化为版本 A 工作?
代码
Box.java
package ser_deser_test;
public class Box {
public Box() {
super();
}
public Elements elements;
public Box(Elements elements) {
super();
this.elements = elements;
}
}
Elements.java
package ser_deser_test;
import java.util.Iterator;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
public class Elements implements Iterable<String> {
// private List<String> elements; // Version A
// public List<String> elements; // Version B
public Elements() {
super();
}
public Elements(List<String> elements) {
super();
this.elements = elements;
}
@Override
public Iterator<String> iterator() {
return elements.iterator();
}
}
TestSerDeser.java
package ser_deser_test;
import java.io.IOException;
import java.util.Arrays;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
public class TestSerDeser {
public static void main(String[] args) {
Elements elements = new Elements(Arrays.asList("a", "b", "c"));
Box box = new Box(elements);
ObjectMapper om = new ObjectMapper();
om.enable(SerializationFeature.INDENT_OUTPUT);
try {
// Serialize
String s = om.writeValueAsString(box);
// Deserialize
Box box2 = om.readValue(s, Box.class);
boolean dummy = false;
} catch (JsonProcessingException e2) {
e2.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
为什么不使用 List<String>
的简单 属性?
public class Elements {
public List<String> elements;
如果您不需要特定对象,也可以作为@EugenCovaci 评论
public class Box {
public List<String> elements; //directly into Box class
为了保持 private List<String> elements;
只需添加 getter 用作 属性:
public List<String> getElements() {
return elements;
}
您还可以添加 @JsonProperty
@JsonProperty
private List<String> elements;
您的代码适用于:
package ser_deser_test;
import java.util.Iterator;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
public class Elements implements Iterable<String> {
// private List<String> elements; // Version A
public List<String> elements; // Version B
public Elements() {
super();
}
public Elements(List<String> elements) {
super();
this.elements = elements;
}
@Override
public Iterator<String> iterator() {
return elements.iterator();
}
}
并因 Version A
被取消注释而失败,因为默认情况下,Jackson 无权访问私有字段。要使其与 Version A
一起使用,请像这样修改 TestSerDeser
class:
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
为了允许 Jackson 访问私有字段 List<String> elements
或者,更好的是,为该字段添加一个 public getter。
我有一个 class Box
,它有一个 elements
类型的字段 Elements
实现了 Iterable
(见下面的代码)。后者包含一个 List
也称为 elements
如果我将 Elements
的字段 elements
设置为 private
,那么序列化会将其视为数组而不是 POJO
版本A完成序列化
{
"elements" : [ "a", "b", "c" ]
}
但是,我无法反序列化这个字符串。错误是:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `ser_deser_test.Elements` out of START_ARRAY token
at [Source: (String)"{
"elements" : [ "a", "b", "c" ]
}"; line: 2, column: 16] (through reference chain:
如果我将 elements
设置为 public
,那么 Box
的 elements
将被视为 POJO,我有这个有趣的两个级别其中有 elements
个。然而,反序列化在这种情况下有效。
按版本 B 序列化
{
"elements" : {
"elements" : [ "a", "b", "c" ]
}
}
我的问题是:我怎样才能让反序列化为版本 A 工作?
代码
Box.java
package ser_deser_test;
public class Box {
public Box() {
super();
}
public Elements elements;
public Box(Elements elements) {
super();
this.elements = elements;
}
}
Elements.java
package ser_deser_test;
import java.util.Iterator;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
public class Elements implements Iterable<String> {
// private List<String> elements; // Version A
// public List<String> elements; // Version B
public Elements() {
super();
}
public Elements(List<String> elements) {
super();
this.elements = elements;
}
@Override
public Iterator<String> iterator() {
return elements.iterator();
}
}
TestSerDeser.java
package ser_deser_test;
import java.io.IOException;
import java.util.Arrays;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
public class TestSerDeser {
public static void main(String[] args) {
Elements elements = new Elements(Arrays.asList("a", "b", "c"));
Box box = new Box(elements);
ObjectMapper om = new ObjectMapper();
om.enable(SerializationFeature.INDENT_OUTPUT);
try {
// Serialize
String s = om.writeValueAsString(box);
// Deserialize
Box box2 = om.readValue(s, Box.class);
boolean dummy = false;
} catch (JsonProcessingException e2) {
e2.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
为什么不使用 List<String>
的简单 属性?
public class Elements {
public List<String> elements;
如果您不需要特定对象,也可以作为@EugenCovaci 评论
public class Box {
public List<String> elements; //directly into Box class
为了保持 private List<String> elements;
只需添加 getter 用作 属性:
public List<String> getElements() {
return elements;
}
您还可以添加 @JsonProperty
@JsonProperty
private List<String> elements;
您的代码适用于:
package ser_deser_test;
import java.util.Iterator;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
public class Elements implements Iterable<String> {
// private List<String> elements; // Version A
public List<String> elements; // Version B
public Elements() {
super();
}
public Elements(List<String> elements) {
super();
this.elements = elements;
}
@Override
public Iterator<String> iterator() {
return elements.iterator();
}
}
并因 Version A
被取消注释而失败,因为默认情况下,Jackson 无权访问私有字段。要使其与 Version A
一起使用,请像这样修改 TestSerDeser
class:
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
为了允许 Jackson 访问私有字段 List<String> elements
或者,更好的是,为该字段添加一个 public getter。