我一整天都在寻找可以回答这个问题的东西,但到目前为止我还没有太多运气。
我的问题很简单:如何使用 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$1",{"value":5}] :
线程“main”com.fasterxml.jackson.databind.JsonMappingException中出现异常:无法将类com.foo.test.JacksonTest$1(本地/匿名类型)反序列化为Bean。
编辑 澄清一下,Jackson 和 XStream 都能够序列化对象。但似乎只有 XStream 能够将对象反序列化回来。所以这个场景可以实现。
在我写这篇文章时,Jackson 似乎没有正确序列化内部类或匿名类。但其他软件包(例如 XStream 和 Kryo)却可以。
因为内部类没有默认的零参数构造函数(它们具有对外部/父类的隐藏引用),Jackson 无法实例化它们。
您可以查看此链接。
问题不仅仅在于它是一个内部类(这可能有问题也可能没有问题,具体取决于实现是静态还是非静态),而且还在于没有包含类型信息——Jackson 看到的只是类型
Interface1
。为了能够读回它,必须包含类型信息(“多态类型处理”),或者指定抽象类型和实现类之间的映射。
假设您使用的是匿名内部类,您将能够通过启用所谓的“默认类型”来支持这种用法(请参阅
ObjectMapper
javadocs 了解 enableDefaultTyping()
等)。
但如果您不想为所有非最终类型启用类型包含,您可能还需要实施特定策略。
要查看是否包含类型 id,您可以使用默认选项之一启用默认类型,并查看生成的 JSON:应该有一个附加的类型 id(当类名用作 id 时为“@class”属性)。
使用嵌套类通过 Jackson 将通用 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 解析和填充。