如何使用 Jackson 在对象中包含原始 JSON? [英] How can I include raw JSON in an object using Jackson?

查看:26
本文介绍了如何使用 Jackson 在对象中包含原始 JSON?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当使用 Jackson 对对象进行(反)序列化时,我试图将原始 JSON 包含在 Java 对象中.为了测试这个功能,我写了以下测试:

公共静态类 Pojo {公共字符串 foo;@JsonRawValue公共字符串栏;}@测试public void test() 抛出 JsonGenerationException、JsonMappingException、IOException {String foo = "一";String bar = "{"A":false}";Pojo pojo = new Pojo();pojo.foo = foo;pojo.bar = 酒吧;String json = "{"foo":"" + foo + "","bar":" + bar + "}";ObjectMapper objectMapper = new ObjectMapper();字符串输出 = objectMapper.writeValueAsString(pojo);System.out.println(输出);assertEquals(json, 输出);Pojo 反序列化 = objectMapper.readValue(output, Pojo.class);assertEquals(foo, deserialized.foo);assertEquals(bar, deserialized.bar);}

代码输出以下行:

{"foo":"one","bar":{"A":false}}

JSON 正是我想要的样子.不幸的是,当尝试将 JSON 读回对象时,代码失败并出现异常.这是一个例外:

<块引用>

org.codehaus.jackson.map.JsonMappingException:无法从 START_OBJECT 令牌反序列化 java.lang.String 的实例在 [来源:java.io.StringReader@d70d7a;行:1,列:13](通过参考链:com.tnal.prism.cobalt.gather.testing.Pojo["bar"])

为什么 Jackson 在一个方向上运行良好,而在另一个方向上却失败了?看起来它应该能够再次将自己的输出作为输入.我知道我正在尝试做的是非正统的(一般建议是为 bar 创建一个内部对象,该对象具有名为 A 的属性),但我没有想要与这个 JSON 进行交互.我的代码充当此代码的传递——我想接收此 JSON 并再次将其发送回去,而不要碰任何东西,因为当 JSON 更改时,我不希望我的代码需要修改.

谢谢你的建议.

使 Pojo 成为静态类,这会导致不同的错误.

解决方案

@JsonRawValue 仅用于序列化端,因为反向处理有点棘手.实际上,添加它是为了允许注入预编码的内容.

我想可以添加对反向的支持,尽管这会很尴尬:必须解析内容,然后重新写回原始"形式,这可能相同也可能不同(因为字符引用可能不同).这对于一般情况.但也许它对某些问题的子集有意义.

但我认为针对您的特定情况的解决方法是将类型指定为java.lang.Object",因为这应该可以正常工作:对于序列化,字符串将按原样输出,对于反序列化,它将被反序列化为 Map.实际上,如果是这样,您可能希望拥有单独的 getter/setter;getter 将返回 String 进行序列化(并且需要 @JsonRawValue);而 setter 将采用 Map 或 Object.如果有意义,您可以将其重新编码为字符串.

I am trying to include raw JSON inside a Java object when the object is (de)serialized using Jackson. In order to test this functionality, I wrote the following test:

public static class Pojo {
    public String foo;

    @JsonRawValue
    public String bar;
}

@Test
public void test() throws JsonGenerationException, JsonMappingException, IOException {

    String foo = "one";
    String bar = "{"A":false}";

    Pojo pojo = new Pojo();
    pojo.foo = foo;
    pojo.bar = bar;

    String json = "{"foo":"" + foo + "","bar":" + bar + "}";

    ObjectMapper objectMapper = new ObjectMapper();
    String output = objectMapper.writeValueAsString(pojo);
    System.out.println(output);
    assertEquals(json, output);

    Pojo deserialized = objectMapper.readValue(output, Pojo.class);
    assertEquals(foo, deserialized.foo);
    assertEquals(bar, deserialized.bar);
}

The code outputs the following line:

{"foo":"one","bar":{"A":false}}

The JSON is exactly how I want things to look. Unfortunately, the code fails with an exception when attempting to read the JSON back in to the object. Here is the exception:

org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token at [Source: java.io.StringReader@d70d7a; line: 1, column: 13] (through reference chain: com.tnal.prism.cobalt.gather.testing.Pojo["bar"])

Why does Jackson function just fine in one direction but fail when going the other direction? It seems like it should be able to take its own output as input again. I know what I'm trying to do is unorthodox (the general advice is to create an inner object for bar that has a property named A), but I don't want to interact with this JSON at all. My code is acting as a pass-through for this code -- I want to take in this JSON and send it back out again without touching a thing, because when the JSON changes I don't want my code to need modifications.

Thanks for the advice.

EDIT: Made Pojo a static class, which was causing a different error.

解决方案

@JsonRawValue is intended for serialization-side only, since the reverse direction is a bit trickier to handle. In effect it was added to allow injecting pre-encoded content.

I guess it would be possible to add support for reverse, although that would be quite awkward: content will have to be parsed, and then re-written back to "raw" form, which may or may not be the same (since character quoting may differ). This for general case. But perhaps it would make sense for some subset of problems.

But I think a work-around for your specific case would be to specify type as 'java.lang.Object', since this should work ok: for serialization, String will be output as is, and for deserialization, it will be deserialized as a Map. Actually you might want to have separate getter/setter if so; getter would return String for serialization (and needs @JsonRawValue); and setter would take either Map or Object. You could re-encode it to a String if that makes sense.

这篇关于如何使用 Jackson 在对象中包含原始 JSON?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆