Java 如何将Jackson与运行时泛型一起使用?
我是Jackson的新手,无法用泛型字段反序列化JSON。这是我想用Jackson解析的JSONJava 如何将Jackson与运行时泛型一起使用?,java,json,generics,jackson,deserialization,Java,Json,Generics,Jackson,Deserialization,我是Jackson的新手,无法用泛型字段反序列化JSON。这是我想用Jackson解析的JSON { "topic": { "headline": { ... }, "body": [ { "type": "complex", "content": { "player_template": "12345", "width": 600, "height":
{
"topic": {
"headline": {
...
},
"body": [
{
"type": "complex",
"content": {
"player_template": "12345",
"width": 600,
"height": 338,
"url": "http://...",
"caption": "foobar",
"vid": "12345",
"watch_url": "http://...",
"embed_html": "<script..."
},
"preview_image_url": "https://...",
"position": 0
},
{
"content": "foobar",
"type": "simple",
"position": 1
}
],
"type": "some type",
"part": "image",
"box_link": [
{
...
},
...
]
}
}
我尝试使用JsonSubTypes
注释将JSON映射到POJO,因此如果type
等于complex
,那么JSON应该映射到Content
类,对于simple
类型,映射类应该是String
对象。问题是,Jackson将复杂的内容转换为LinkedHashMap
我不想要的内容。对于simple
内容没有问题,它将被转换为String
,但我认为Jackson使用内部逻辑来映射这种正确的方式
如果我尝试使用JsonDeserialize
注释,则不会调用反序列化程序方法。这就好像杰克逊忽略了注释而自己创作
我在哪里犯了错误?如何将complex
内容解析为content
POJO?@JsonTypeInfo
和@JsonSubTypes
旨在帮助继承而不是泛型。由于字符串
和内容
都隐式扩展了对象
,因此可以将mContent
定义为对象
。下面是您的Body
类的外观:
class Body {
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = String.class, name = "simple"),
@JsonSubTypes.Type(value = Content.class, name = "complex")
})
@JsonProperty("content")
private Object mContent;
当您指定
include = JsonTypeInfo.As.PROPERTY
Jackson将在JSON中的content
字段中查找type
。但是在您的例子中,类型
位于JSON中主体
数组的元素中,与内容
处于同一级别。在这种情况下,您必须指定
include = JsonTypeInfo.As.EXTERNAL_PROPERTY
因此,Jackson将在JSON中的content
字段之外查找type
请记住,如果您有一个像Body
这样的泛型类,则必须向Jackson提供类型T
,以便进行反序列化(例如,使用类型引用
)。如果你想将Body
和Body
放在同一个集合/数组中,我看不出这是怎么回事。集合的类型必须是不再通用的List
。我已通过使用自定义JsonDeserializer
解决了此问题
@JsonDeserialize(using = BodyDeserializer.class)
public class Body<T> {
@JsonProperty("content")
private T mContent;
@JsonProperty("type")
private String mType;
@JsonProperty("preview_image_url")
private String mPreviewImageUrl;
@JsonProperty("position")
private int mPosition;
// getter and setter
}
public class BodyDeserializer extends StdDeserializer<Body> {
private static final String CAPTION = "caption";
private static final String CONTENT = "content";
private static final String COMPLEX = "complex";
private static final String EMBED_HTML = "embed_html";
private static final String HEIGHT = "height";
private static final String PLAYER_TEMPLATE = "player_template";
private static final String POSITION = "position";
private static final String PREVIEW_IMAGE_URL = "preview_image_url";
private static final String PROVIDER = "provider";
private static final String TYPE = "type";
private static final String URL = "url";
private static final String VID = "vid";
private static final String WATCH_URL = "watch_url";
private static final String WIDTH = "width";
public BodyDeserializer() {
this(Body.class);
}
protected BodyDeserializer(Class<Body> vc) {
super(vc);
}
@Override
public Body deserialize(JsonParser parser, DeserializationContext context) throws IOException {
final ObjectCodec oc = parser.getCodec();
final JsonNode node = oc.readTree(parser);
return deserialize(node);
}
private Body deserialize(JsonNode node) {
final String type = node.get(TYPE).asText();
if (COMPLEX.equals(type)) {
return deserializeToBodyWithContent(node, type);
} else {
return deserializeToBodyWithString(node, type);
}
}
private Body deserializeToBodyWithString(JsonNode node, String type) {
final int position = node.get(POSITION).asInt();
return new Body<String>().setContent(node.get(CONTENT).asText()).setType(type).setPosition(position);
}
private Body deserializeToBodyWithContent(JsonNode node, String type) {
final int position = node.get(POSITION).asInt();
final String provider = node.get(PROVIDER).asText();
final String previewImageUrl = node.get(PREVIEW_IMAGE_URL).asText();
return new Body<Content>().setContent(createContent(node.get(CONTENT)))
.setType(type)
.setProvider(provider)
.setPreviewImageUrl(previewImageUrl)
.setPosition(position);
}
private Content createContent(JsonNode node) {
final int width = node.get(WIDTH).asInt();
final int height = node.get(HEIGHT).asInt();
final String vid = node.get(VID).asText();
final String url = node.get(URL).asText();
final String caption = node.get(CAPTION).asText();
final String watchUrl = node.get(WATCH_URL).asText();
final String embedHtml = node.get(EMBED_HTML).asText();
final String playerTemplate = node.get(PLAYER_TEMPLATE).asText();
return new Content().setPlayerTemplate(playerTemplate)
.setWidth(width)
.setHeight(height)
.setUrl(url)
.setCaption(caption)
.setVid(vid)
.setWatchUrl(watchUrl)
.setEmbedHtml(embedHtml);
}
}
@JsonDeserialize(使用=BodyDeserializer.class)
公共阶级团体{
@JsonProperty(“内容”)
私有内容;
@JsonProperty(“类型”)
私有字符串mType;
@JsonProperty(“预览图像url”)
私有字符串mPreviewImageUrl;
@JsonProperty(“职位”)
私人投资;
//接二连三
}
公共类BodyDeserializer扩展StdDeserializer{
私有静态最终字符串CAPTION=“CAPTION”;
私有静态最终字符串CONTENT=“CONTENT”;
私有静态最终字符串COMPLEX=“COMPLEX”;
私有静态最终字符串EMBED\u HTML=“EMBED\u HTML”;
私有静态最终字符串高度=“高度”;
私有静态最终字符串播放器\ u TEMPLATE=“播放器\ u TEMPLATE”;
私有静态最终字符串POSITION=“POSITION”;
私有静态最终字符串PREVIEW\u IMAGE\u URL=“PREVIEW\u IMAGE\u URL”;
私有静态最终字符串PROVIDER=“PROVIDER”;
私有静态最终字符串TYPE=“TYPE”;
私有静态最终字符串URL=“URL”;
私有静态最终字符串VID=“VID”;
私有静态最终字符串WATCH\u URL=“WATCH\u URL”;
私有静态最终字符串宽度=“宽度”;
公共BodyDeserializer(){
这个(Body.class);
}
受保护的BodyDeserializer(vc类){
超级(vc);
}
@凌驾
公共体反序列化(JsonParser解析器,反序列化上下文)引发IOException{
final ObjectCodec oc=parser.getCodec();
final-JsonNode=oc.readTree(解析器);
返回反序列化(节点);
}
私有主体反序列化(JsonNode节点){
最终字符串类型=node.get(type).asText();
if(复数等于(类型)){
返回反序列化的ZetoBodyWithContent(节点,类型);
}否则{
返回反序列化ZetoBodyWithString(节点,类型);
}
}
私有主体反序列化ToBodyWithString(JsonNode节点,字符串类型){
final int position=node.get(position.asInt();
返回新的Body().setContent(node.get(CONTENT).asText()).setType(type).setPosition(position);
}
私有主体反序列化ToBodyWithContent(JsonNode节点,字符串类型){
final int position=node.get(position.asInt();
final String provider=node.get(provider.astex();
最终字符串previewImageUrl=node.get(PREVIEW\u IMAGE\u URL.asText();
返回新的Body().setContent(createContent(node.get(CONTENT)))
.setType(类型)
.setProvider(提供程序)
.setPreviewImageUrl(previewImageUrl)
.设置位置(位置);
}
私有内容createContent(JsonNode节点){
final int width=node.get(width.asInt();
final int height=node.get(height).asInt();
最后一个字符串vid=node.get(vid.asText();
最后一个字符串url=node.get(url.asText();
最后一个字符串caption=node.get(caption.asText();
最后一个字符串watchUrl=node.get(WATCH_URL.asText();
最后一个字符串embedHtml=node.get(EMBED_HTML).asText();
最后一个字符串playerTemplate=node.get(PLAYER_-TEMPLATE).asText();
返回新内容().setPlayerTemplate(playerTemplate)
.setWidth(宽度)
.setHeight(高度)
.setUrl(url)
.setCaption(标题)
.setVid(vid)
.setWatchUrl(watchUrl)
.setEmbedHtml(embedHtml);
}
}
这不是最好的解决方案,但它是有效的。我现在使用,它有点简单。感谢您的解释,但不幸的是它给出了相同的结果LinkedHashMap
。
@JsonDeserialize(using = BodyDeserializer.class)
public class Body<T> {
@JsonProperty("content")
private T mContent;
@JsonProperty("type")
private String mType;
@JsonProperty("preview_image_url")
private String mPreviewImageUrl;
@JsonProperty("position")
private int mPosition;
// getter and setter
}
public class BodyDeserializer extends StdDeserializer<Body> {
private static final String CAPTION = "caption";
private static final String CONTENT = "content";
private static final String COMPLEX = "complex";
private static final String EMBED_HTML = "embed_html";
private static final String HEIGHT = "height";
private static final String PLAYER_TEMPLATE = "player_template";
private static final String POSITION = "position";
private static final String PREVIEW_IMAGE_URL = "preview_image_url";
private static final String PROVIDER = "provider";
private static final String TYPE = "type";
private static final String URL = "url";
private static final String VID = "vid";
private static final String WATCH_URL = "watch_url";
private static final String WIDTH = "width";
public BodyDeserializer() {
this(Body.class);
}
protected BodyDeserializer(Class<Body> vc) {
super(vc);
}
@Override
public Body deserialize(JsonParser parser, DeserializationContext context) throws IOException {
final ObjectCodec oc = parser.getCodec();
final JsonNode node = oc.readTree(parser);
return deserialize(node);
}
private Body deserialize(JsonNode node) {
final String type = node.get(TYPE).asText();
if (COMPLEX.equals(type)) {
return deserializeToBodyWithContent(node, type);
} else {
return deserializeToBodyWithString(node, type);
}
}
private Body deserializeToBodyWithString(JsonNode node, String type) {
final int position = node.get(POSITION).asInt();
return new Body<String>().setContent(node.get(CONTENT).asText()).setType(type).setPosition(position);
}
private Body deserializeToBodyWithContent(JsonNode node, String type) {
final int position = node.get(POSITION).asInt();
final String provider = node.get(PROVIDER).asText();
final String previewImageUrl = node.get(PREVIEW_IMAGE_URL).asText();
return new Body<Content>().setContent(createContent(node.get(CONTENT)))
.setType(type)
.setProvider(provider)
.setPreviewImageUrl(previewImageUrl)
.setPosition(position);
}
private Content createContent(JsonNode node) {
final int width = node.get(WIDTH).asInt();
final int height = node.get(HEIGHT).asInt();
final String vid = node.get(VID).asText();
final String url = node.get(URL).asText();
final String caption = node.get(CAPTION).asText();
final String watchUrl = node.get(WATCH_URL).asText();
final String embedHtml = node.get(EMBED_HTML).asText();
final String playerTemplate = node.get(PLAYER_TEMPLATE).asText();
return new Content().setPlayerTemplate(playerTemplate)
.setWidth(width)
.setHeight(height)
.setUrl(url)
.setCaption(caption)
.setVid(vid)
.setWatchUrl(watchUrl)
.setEmbedHtml(embedHtml);
}
}