Jackson反序列化映射到Java泛型
我试图做的是:给定一个JSON文档,使用Jackson将其映射到POJO,但根据JSON文档中的字段定义泛型类成员的类型Jackson反序列化映射到Java泛型,java,json,generics,jackson,Java,Json,Generics,Jackson,我试图做的是:给定一个JSON文档,使用Jackson将其映射到POJO,但根据JSON文档中的字段定义泛型类成员的类型 @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="@type") @JsonSubTypes({ @JsonSubTypes.Type(value=ParameterString.class, name="string"), @JsonSubT
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="@type")
@JsonSubTypes({
@JsonSubTypes.Type(value=ParameterString.class, name="string"),
@JsonSubTypes.Type(value=ParameterDouble.class, name="double"),
@JsonSubTypes.Type(value=ParameterInstrument.class, name="instrument")
})
我的JSON如下所示
{
"name": "Name",
"parameters": [
{"name": "paramName","value": "Value1", "@type": "string"},
{"name": "size","value": 5,"@type": "double"}
]
}
public class Parameter<T> {
public String name;
public T value;
@Override
public String toString() {
return this.getClass().getName();
}
}
映射到此JSON文档的类是
public class Strategy {
public String name;
public List<Parameter<?>> parameters;
}
但是按原样使用这些类实际上是可行的,但是Jackson根据其值自行决定类型,并且my size参数设置为整数。如果我将它的值设置为5.0,那么它的值设置为一个Double,这是可行的,但是如果我希望其中一个参数是自定义对象呢
我能让它工作的唯一方法(我对解决方案不是100%满意)是使参数类抽象,然后为我想要的每种类型创建具体的类,即ParameterString、ParameterDouble、,参数CustomClass,然后使用@JsonSubTypes注释根据JSON文档中的type字段设置要使用的正确类
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="@type")
@JsonSubTypes({
@JsonSubTypes.Type(value=ParameterString.class, name="string"),
@JsonSubTypes.Type(value=ParameterDouble.class, name="double"),
@JsonSubTypes.Type(value=ParameterInstrument.class, name="instrument")
})
以下面的类为例
public class StrategyParameterString extends StrategyParameter<String> {
}
公共类StrategyParameterString扩展StrategyParameter{
}
这不是很好扩展,我想它只需要为我需要的每一种类型添加一个新的子类型注释和具体类,但感觉并不像可能的那么优雅
有人知道更好的处理方法吗
谢谢
Andrew据我所知,您希望在
参数
列表中表示的类型是可修改的,例如String、Double、Instrument。您可以利用这样一个事实,即可重新定义的类型有一个以类文本形式表示的运行时类型标记。可以利用它来形成异构类型安全集合的基础
不要这样定义参数类:
public class Parameter<T> {
public String name;
public T value;
:
:
}
}
公共类参数{
公共字符串名称;
公共价值观;
:
:
}
}
您可以将其定义为一个具体的类,该类将对象的值与其运行时类型标记相关联
public class Parameter() {
private final Object m_value;
private final Class<?> m_cls;
private Parameter(Class<?> token, Object val) {
m_value = val;
m_cls = token;
}
public static <T> Parameter newInstance(Class<T> token, T value) {
return new Parameter(token, value);
}
:
:
public <T> T getValue(Class<T> token) {
if (token != m_cls) throw new ClassCastException("Type error");
return token.cast(m_value);
}
}
公共类参数(){
私有最终对象m_值;
私立期末班m_cls;
私有参数(类令牌、对象val){
m_值=val;
m_cls=令牌;
}
公共静态参数newInstance(类标记,T值){
返回新参数(令牌、值);
}
:
:
公共T getValue(类令牌){
如果(token!=m_cls)抛出新的ClassCastException(“类型错误”);
返回令牌.cast(m_值);
}
}
在此设置中,使用类型标记和泛型方法(而不是泛型类型)来设置和重新建立所需值的类型链接。您设置的值可以是任何类型,并且只要类型标记一致,就可以保证返回与存储的类型相同的值
请注意,构造函数不能是泛型的。为了解决这个问题,参数的构造函数被设置为私有的,参数实例是通过调用
newInstance()
静态工厂方法(可以是泛型的)形成的。我只是好奇为什么要这样做。Java通过擦除实现泛型类型。这意味着泛型类型参数存在,并且只有在编译时才有意义。它们在运行时不存在。您的列表的运行时类
对象感谢您的评论@scottb。基本上,我是通过为我需要的每种类型创建一个类,让它们实现一个接口,并让我的列表来实现这一点的,这里有两个问题,首先当我迭代列表时,对象不知道任何关于类成员的事,除非我强制转换它,其次每个类都有重复的代码,因此,我将其重构为一个基本抽象类,以减少代码重复。我猜具体的类实现在编译时设置类型,因此这可能是一种比Java擦除更好的处理方式。为了让我理解您在上面写的这个参数类,它有两个字段:值(m_value)和值表示的类(m_cls),这就是为什么getValue方法将值转换为正确的类类型?我想知道这是否适用于Jackson反序列化?Class
是可序列化的(并且类是可修改的)。如果项目中的其他引用类型也是可序列化的,我不明白为什么不能使其工作。可能需要省略getValue()
方法中的比较。问题是主机平台上的检查断言对象值的类型与所请求的类型相同。可能无法在客户端上工作。如果省略了检查,则未选中强制转换;无法保证您会请求与存储的类型相同的类型。