我有一个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代表什么呢?
Answers:
您需要为使用的TypeReference
每种通用类型创建一个对象,并将其用于反序列化。例如 -
mapper.readValue(jsonString, new TypeReference<Data<String>>() {});
Data<T>
,那不是一种类型。您必须指定实际班级;否则与相同Data<Object>
。
TypeReference
什么?是com.fasterxml.jackson.core.type
吗
您不能这样做:您必须指定完全解析的类型,例如Data<MyType>
。T
只是一个变量,没有意义。
但是,如果您想T
知道的只是静态的,则需要创建TypeReference
动态等效项。引用的其他问题可能已经提到了这一点,但它看起来应该像这样:
public Data<T> read(InputStream json, Class<T> contentClass) {
JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, contentClass);
return mapper.readValue(json, type);
}
TypeReference
:return mapper.readValue(json, clazz);
在这里到底是什么问题?
TypeFactory
..我将编辑我的答案。
首先要做的是序列化,然后可以进行反序列化。
因此,当您进行序列化时,应该@JsonTypeInfo
使杰克逊将类信息写入json数据。您可以做的是这样的:
Class Data <T> {
int found;
@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class")
Class<T> hits
}
然后,当您反序列化时,您会发现杰克逊将数据反序列化为一个类,您的变量命中实际上是在运行时。
对于类Data <>
ObjectMapper mapper = new ObjectMapper();
JavaType type = mapper.getTypeFactory().constructParametrizedType(Data.class, Data.class, Parameter.class);
Data<Parameter> dataParam = mapper.readValue(jsonString,type)
只需在Util类中编写一个静态方法。我正在从文件中读取Json。您也可以将String设置为readValue
public static <T> T convertJsonToPOJO(String filePath, Class<?> target) throws JsonParseException, JsonMappingException, IOException, ClassNotFoundException {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(new File(filePath), objectMapper .getTypeFactory().constructCollectionType(List.class, Class.forName(target.getName())));
}
用法:
List<TaskBean> list = Util.<List<TaskBean>>convertJsonToPOJO("E:/J2eeWorkspaces/az_workspace_svn/az-client-service/dir1/dir2/filename.json", TaskBean.class);
需要反序列化的JSON字符串将必须包含有关parameter的类型信息T
。
您将必须在每个可以作为参数传递T
给类的类上放置Jackson批注,以便Jackson 可以从JSON字符串中读取/写入Data
参数类型的类型信息T
。
让我们假设T
该类可以是扩展抽象类的任何类Result
。
class Data <T extends Result> {
int found;
Class<T> hits
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
@JsonSubTypes({
@JsonSubTypes.Type(value = ImageResult.class, name = "ImageResult"),
@JsonSubTypes.Type(value = NewsResult.class, name = "NewsResult")})
public abstract class Result {
}
public class ImageResult extends Result {
}
public class NewsResult extends Result {
}
一旦T
注释了可以作为参数传递的每个类(或其公共超类型),Jackson将T
在JSON中包含有关参数的信息。然后,可以T
在编译时不知道参数的情况下反序列化此类JSON 。
这个Jackson文档链接讨论了多态反序列化,但是对于这个问题也很有用。
从Jackson 2.5开始,一种优雅的解决方法是使用TypeFactory.constructParametricType(Class parametrized,Class ... parameterClasses)方法,该方法允许JavaType
通过指定参数化类及其参数化类型来
严格定义Jackson 。
假设要反序列化为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);
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;
}
...
}
如果您使用的是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)
要使用Jackson将通用JSON字符串反序列化为Java对象,您需要:
定义JSON类。
执行属性映射。
最终代码,经过测试,可以立即使用:
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分析和填充。
有关嵌套数组的更复杂情况,请参见Baeldung参考:https ://www.baeldung.com/jackson-mapping-dynamic-object