我有一个json字符串,我应该反序列化到下面的类
class Data <T> {
int found;
Class<T> hits
}
我该怎么做? 这是通常的做法
mapper.readValue(jsonString, Data.class);
但是我怎么提到T代表什么呢?
我有一个json字符串,我应该反序列化到下面的类
class Data <T> {
int found;
Class<T> hits
}
我该怎么做? 这是通常的做法
mapper.readValue(jsonString, Data.class);
但是我怎么提到T代表什么呢?
当前回答
如果你正在使用scala,并且在编译时知道泛型类型,但不想在所有api层中手动传递TypeReference,你可以使用以下代码(使用jackson 2.9.5):
def read[T](entityStream: InputStream)(implicit typeTag: WeakTypeTag[T]): T = {
//nathang: all of this *crazy* scala reflection allows us to handle List[Seq[Map[Int,Value]]]] without passing
// new TypeReference[List[Seq[Map[Int,Value]]]]](){} to the function
def recursiveFindGenericClasses(t: Type): JavaType = {
val current = typeTag.mirror.runtimeClass(t)
if (t.typeArgs.isEmpty) {
val noSubtypes = Seq.empty[Class[_]]
factory.constructParametricType(current, noSubtypes:_*)
}
else {
val genericSubtypes: Seq[JavaType] = t.typeArgs.map(recursiveFindGenericClasses)
factory.constructParametricType(current, genericSubtypes:_*)
}
}
val javaType = recursiveFindGenericClasses(typeTag.tpe)
json.readValue[T](entityStream, javaType)
}
可以这样使用:
read[List[Map[Int, SomethingToSerialize]]](inputStream)
其他回答
你可以把它包装在另一个类中,这个类知道你的泛型类型的类型。
Eg,
class Wrapper {
private Data<Something> data;
}
mapper.readValue(jsonString, Wrapper.class);
这里Something是一个具体的类型。每个具体化类型都需要一个包装器。否则Jackson就不知道该创建什么对象。
您需要为所使用的每个泛型类型创建一个TypeReference对象,并使用该对象进行反序列化。例如:
mapper.readValue(jsonString, new TypeReference<Data<String>>() {});
如果你正在使用scala,并且在编译时知道泛型类型,但不想在所有api层中手动传递TypeReference,你可以使用以下代码(使用jackson 2.9.5):
def read[T](entityStream: InputStream)(implicit typeTag: WeakTypeTag[T]): T = {
//nathang: all of this *crazy* scala reflection allows us to handle List[Seq[Map[Int,Value]]]] without passing
// new TypeReference[List[Seq[Map[Int,Value]]]]](){} to the function
def recursiveFindGenericClasses(t: Type): JavaType = {
val current = typeTag.mirror.runtimeClass(t)
if (t.typeArgs.isEmpty) {
val noSubtypes = Seq.empty[Class[_]]
factory.constructParametricType(current, noSubtypes:_*)
}
else {
val genericSubtypes: Seq[JavaType] = t.typeArgs.map(recursiveFindGenericClasses)
factory.constructParametricType(current, genericSubtypes:_*)
}
}
val javaType = recursiveFindGenericClasses(typeTag.tpe)
json.readValue[T](entityStream, javaType)
}
可以这样使用:
read[List[Map[Int, SomethingToSerialize]]](inputStream)
public class Data<T> extends JsonDeserializer implements ContextualDeserializer {
private Class<T> cls;
public JsonDeserializer createContextual(DeserializationContext ctx, BeanProperty prop) throws JsonMappingException {
cls = (Class<T>) ctx.getContextualType().getRawClass();
return this;
}
...
}
从Jackson 2.5开始,一种优雅的解决方法是使用 TypeFactory。类参数化,类…parameterClasses)方法,该方法允许通过指定参数化类及其参数化类型直接定义Jackson JavaType。
假设你想反序列化到Data<String>,你可以这样做:
// the json variable may be a String, an InputStream and so for...
JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, String.class);
Data<String> data = mapper.readValue(json, type);
注意,如果类声明了多个参数化类型,它并不会变得更难:
class Data <T, U> {
int found;
Class<T> hits;
List<U> list;
}
我们可以这样做:
JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, String.class, Integer);
Data<String, Integer> data = mapper.readValue(json, type);