使用匿名 类 的 Jackson 反序列化
Jackson deserialization with anonymous classes
我整天都在寻找能回答这个问题的东西,但到目前为止我运气不太好。
我的问题很简单:如何使用 Jackson 正确反序列化匿名对象。
private interface Interface1
{
int getValue();
}
public static void testAnonymousObject() throws IOException
{
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
Interface1 testObject = new Interface1()
{
private final int value = 5;
@Override
public int getValue()
{
return value;
}
};
String json = mapper.writeValueAsString(testObject);
System.out.println("JSON = " + json);
Interface1 received = (Interface1) mapper.readValue(json, Object.class);
System.out.println(received);
}
这个输出是:JSON = ["com.foo.test.JacksonTest",{"value":5}] 在我得到异常之前:
线程"main"com.fasterxml.jackson.databind.JsonMappingException中的异常:无法将Classcom.foo.test.JacksonTest$1(类型local/anonymous)反序列化为Bean .
EDIT 澄清一下,Jackson 和 XStream 都能够序列化该对象。但似乎只有 XStream 能够反序列化对象。所以这个场景可以实现。
问题不仅仅在于它是一个内部 class(这可能有问题也可能没有问题,具体取决于实现是静态的还是非静态的),还在于没有包含类型信息 - - Jackson 看到的都是类型 Interface1
。为了能够读回它,必须包含类型信息 ("polymorphic type handling"),或者指定抽象类型和实现之间的映射 class.
鉴于您正在使用匿名内部 class,您将能够通过启用所谓的 "default typing" 来支持这种用法(请参阅 ObjectMapper
javadocs 了解 enableDefaultTyping()
之类的)。
但如果您不想为所有非最终类型启用类型包含,您可能还需要实施特定策略。
要查看是否包含类型 ID,您可以使用默认选项之一启用默认类型,并查看正在生成的 JSON:应该有一个额外的类型 ID ("@class " 属性 当 class 名称用作 id 时)。
截至我撰写本文时,Jackson 似乎没有正确序列化内部 类 或匿名 类。但是,XStream 和 Kryo 等其他软件包可以。
因为内部 classes 没有默认的零参数构造函数(它们有对 outer/parent class 的隐藏引用)Jackson 无法实例化它们。
你可以检查这个link
使用嵌套 类:
的通用 JSON 反序列化为 Java POJO 的现成代码片段
static class MyJSON {
private Map<String, Object> content = new HashMap<>();
@JsonAnySetter
public void setContent(String key, Object value) {
content.put(key, value);
}
}
String json = "{\"City\":\"Prague\"}";
try {
MyPOJO myPOJO = objectMapper.readValue(json, MyPOJO.class);
String jsonAttVal = myPOJO.content.get("City").toString();
System.out.println(jsonAttVal);
} catch (IOException e) {
e.printStackTrace();
}
@JsonAnySetter
确保通用 JSON-解析和填充。
我整天都在寻找能回答这个问题的东西,但到目前为止我运气不太好。
我的问题很简单:如何使用 Jackson 正确反序列化匿名对象。
private interface Interface1
{
int getValue();
}
public static void testAnonymousObject() throws IOException
{
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
Interface1 testObject = new Interface1()
{
private final int value = 5;
@Override
public int getValue()
{
return value;
}
};
String json = mapper.writeValueAsString(testObject);
System.out.println("JSON = " + json);
Interface1 received = (Interface1) mapper.readValue(json, Object.class);
System.out.println(received);
}
这个输出是:JSON = ["com.foo.test.JacksonTest",{"value":5}] 在我得到异常之前:
线程"main"com.fasterxml.jackson.databind.JsonMappingException中的异常:无法将Classcom.foo.test.JacksonTest$1(类型local/anonymous)反序列化为Bean .
EDIT 澄清一下,Jackson 和 XStream 都能够序列化该对象。但似乎只有 XStream 能够反序列化对象。所以这个场景可以实现。
问题不仅仅在于它是一个内部 class(这可能有问题也可能没有问题,具体取决于实现是静态的还是非静态的),还在于没有包含类型信息 - - Jackson 看到的都是类型 Interface1
。为了能够读回它,必须包含类型信息 ("polymorphic type handling"),或者指定抽象类型和实现之间的映射 class.
鉴于您正在使用匿名内部 class,您将能够通过启用所谓的 "default typing" 来支持这种用法(请参阅 ObjectMapper
javadocs 了解 enableDefaultTyping()
之类的)。
但如果您不想为所有非最终类型启用类型包含,您可能还需要实施特定策略。
要查看是否包含类型 ID,您可以使用默认选项之一启用默认类型,并查看正在生成的 JSON:应该有一个额外的类型 ID ("@class " 属性 当 class 名称用作 id 时)。
截至我撰写本文时,Jackson 似乎没有正确序列化内部 类 或匿名 类。但是,XStream 和 Kryo 等其他软件包可以。
因为内部 classes 没有默认的零参数构造函数(它们有对 outer/parent class 的隐藏引用)Jackson 无法实例化它们。
你可以检查这个link
使用嵌套 类:
的通用 JSON 反序列化为 Java POJO 的现成代码片段static class MyJSON {
private Map<String, Object> content = new HashMap<>();
@JsonAnySetter
public void setContent(String key, Object value) {
content.put(key, value);
}
}
String json = "{\"City\":\"Prague\"}";
try {
MyPOJO myPOJO = objectMapper.readValue(json, MyPOJO.class);
String jsonAttVal = myPOJO.content.get("City").toString();
System.out.println(jsonAttVal);
} catch (IOException e) {
e.printStackTrace();
}
@JsonAnySetter
确保通用 JSON-解析和填充。