Java Jackson反序列化嵌套多态类型
我试图使用Jakson反序列化嵌套多态类型。这意味着我的顶级类型引用了另一个多态类型,它最终由非抽象类扩展。这不起作用,它会引发异常 下面是一个我正在尝试做的简化示例Java Jackson反序列化嵌套多态类型,java,json,jackson,Java,Json,Jackson,我试图使用Jakson反序列化嵌套多态类型。这意味着我的顶级类型引用了另一个多态类型,它最终由非抽象类扩展。这不起作用,它会引发异常 下面是一个我正在尝试做的简化示例 package com.adfin; import junit.framework.TestCase; import org.codehaus.jackson.annotate.JsonSubTypes; import org.codehaus.jackson.annotate.JsonTypeInfo; import org.
package com.adfin;
import junit.framework.TestCase;
import org.codehaus.jackson.annotate.JsonSubTypes;
import org.codehaus.jackson.annotate.JsonTypeInfo;
import org.codehaus.jackson.map.ObjectMapper;
import java.io.IOException;
public class JaksonDouble extends TestCase {
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "name"
)
@JsonSubTypes({
@JsonSubTypes.Type(value = SecondLevel.class, name = "SECOND")
})
public static abstract class FirstLevel {
public abstract String getTestValue();
}
@JsonTypeInfo(
use = JsonTypeInfo.Id.CLASS,
include = JsonTypeInfo.As.PROPERTY,
property = "@class"
)
public static abstract class SecondLevel extends FirstLevel {
}
public static class FinalLevel extends SecondLevel {
String test;
@Override public String getTestValue() { return test; }
}
public void testDoubleAbstract() throws IOException {
String testStr = "{ \"name\": \"SECOND\", \"@class\": \"com.adfin.JasksonDouble.FinalLevel\", \"test\": \"foo\"}";
ObjectMapper mapper = new ObjectMapper();
FirstLevel result = mapper.readValue(testStr, FirstLevel.class);
}
}
我得到了关于抽象类型的标准例外
org.codehaus.jackson.map.JsonMappingException: Can not construct instance of com.adfin.JaksonDouble$SecondLevel, problem: abstract types can only be instantiated with additional type information at [Source: java.io.StringReader@f2a55aa; line: 1, column: 19]
让我解释一下我的用例。我有一个Json文档,描述了关于数据的工作流。我在“一级”有一个抽象类型,它描述了对单个值的操作。我派生了一系列实现公共操作的非抽象类(我用@JsonSubTypes注释了所有这些类)
我有一个特殊的@JsonSubTypes,叫做“CUSTOM”。这是另一个抽象类,表示其他人编写的自定义操作(在普通jar之外),他们可以使用“@class”属性指定完全限定的类名。看起来Jakson解析器从未读取第二个lavel类上的@JsonTypeInfo注释
我怎样才能做到这一点。或者至少我该如何使这个用例工作。首先,json中的类名是错误的,应该是com.adfin.JasksonDouble$FinalLevel,dollar而不是dot 这是一个有效的代码,但我不确定它是否正确地回答了所有子类型的问题
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
public static abstract class FirstLevel {
public abstract String getTestValue();
}
从其他类中删除注释,它应该可以工作(只是测试了它)
然而,所有这些东西看起来都很复杂,如果你有时间尝试另一个库,你可能想看看。
要启用多态类型支持,必须配置Genson实例。如果您也是生成json的人,那么您不需要其他任何东西(因为您可以根据需要使用Genson生成json流来处理多态类型)
以下是一个例子:
// enable polymorphic types support
Genson genson = new Genson.Builder().setWithClassMetadata(true).create();
// the @class must be first property in the json object
String testStr = "{ \"@class\": \"com.adfin.JasksonDouble$FinalLevel\", \"test\": \"foo\"}";
FirstLevel result = genson.deserialize(testStr, FirstLevel.class);
System.out.println(result.getTestValue());
Genson的另一个优点是,它使您能够为类注册别名,因此您不必在流中提供所有包信息。另一个优点是,如果在数据库中存储json流并将类移动到另一个包中,则只需更改应用程序中的别名,而不必从数据库迁移所有json流
Genson genson = new Genson.Builder().setWithClassMetadata(true)
.addAlias("FinalLevel", FinalLevel.class)
.create();
// the @class must be first property in the json object
String testStr = "{ \"@class\": \"FinalLevel\", \"test\": \"foo\"}";
FirstLevel result = genson.deserialize(testStr, FirstLevel.class);
System.out.println(result.getTestValue());
您的定义很混乱--您试图使用两个类型标识符,类型名称和类。这没有任何意义。你应该选择一种或另一种方法,而不是两种都选择 如果选择Java类名作为类型信息,只需省略名称即可。另外,对于
第一级
,您只需要包含@JsonTypeInfo
;子类继承此定义
如果您更喜欢使用逻辑类型名称,请删除class属性。您还需要使用注释或通过ObjectMapper
注册子类型列表来指定子类型列表