我怎样才能包括使用jackson的对象的原始JSON?

我试图包括一个Java对象的原始JSON时,对象是(德)序列化使用jackson。 为了testing这个function,我写了下面的testing:

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); } 

该代码输出以下行:

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

JSON正是我想要的东西。 不幸的是,当试图将JSON读回到对象时,代码失败,出现exception。 这是一个例外:

org.codehaus.jackson.map.JsonMappingException:不能在[Source:java.io.StringReader@d70d7a;}处的START_OBJECT标记中反序列化java.lang.String的实例。 行:1,列:13](通过引用链:com.tnal.prism.cobalt.gather.testing.Pojo [“bar”])

为什么jackson在一个方向上的function很好,但是当朝另一个方向时却失败了? 似乎应该能够把自己的输出再次作为input。 我知道我想要做的是非正统的(一般的build议是创build一个名为A属性的bar的内部对象),但我不想与这个JSON进行交互。 我的代码是作为这个代码的传递 – 我想采取这个JSON,并再次发送它不接触的东西,因为当JSON的变化,我不希望我的代码需要修改。

感谢您的build议。

编辑:使Pojo静态类,这是导致不同的错误。

@JsonRawValue仅用于序列化方面,因为相反的方向有点棘手。 实际上,它被添加来允许注入预编码的内容。

我想可以添加对reverse的支持,虽然这样做会很尴尬:内容必须被parsing,然后重新写回到“raw”forms,这可能也可能不一样(因为字符引用可能不同)。 这是一般情况。 但也许这对一些问题是有意义的。

但我认为你的具体情况的解决方法是将types指定为“java.lang.Object”,因为这应该工作正常:对于序列化,string将按原样输出,而对于反序列化,它将被反序列化为一张地图。 其实你可能想要单独的getter / setter,如果是这样的话; getter会返回string序列化(并需要@JsonRawValue); 并且setter将会使用Map或Object。 如果有意义的话,你可以将它重新编码为一个string。

在@StaxMan之后,我做了如下的作品:

 public class Pojo { Object json; @JsonRawValue public String getJson() { // default raw value: null or "[]" return json == null ? null : json.toString(); } public void setJson(JsonNode node) { this.json = node; } } 

而且,要忠实于最初的问题,这里是工作testing:

 public class PojoTest { ObjectMapper mapper = new ObjectMapper(); @Test public void test() throws IOException { Pojo pojo = new Pojo("{\"foo\":18}"); String output = mapper.writeValueAsString(pojo); assertThat(output).isEqualTo("{\"json\":{\"foo\":18}}"); Pojo deserialized = mapper.readValue(output, Pojo.class); assertThat(deserialized.json.toString()).isEqualTo("{\"foo\":18}"); // deserialized.json == {"foo":18} } } 

我可以用一个自定义的反序列化器(从这里剪切和粘贴)

 package etc; import java.io.IOException; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.TreeNode; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; /** * Keeps json value as json, does not try to deserialize it * @author roytruelove * */ public class KeepAsJsonDeserialzier extends JsonDeserializer<String> { @Override public String deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { TreeNode tree = jp.getCodec().readTree(jp); return tree.toString(); } } 

@JsonSetter可能会有帮助。 看我的示例('数据'应该包含未分析的JSON):

 class Purchase { String data; @JsonProperty("signature") String signature; @JsonSetter("data") void setData(JsonNode data) { this.data = data.toString(); } } 

这是你的内部类的问题。 Pojo类是testing类的非静态内部类,Jackson不能实例化该类。 所以它可以序列化,但不能反序列化。

重新定义你的class级:

 public static class Pojo { public String foo; @JsonRawValue public String bar; } 

注意添加static

添加到Roy Truelove的伟大的答案 ,这是如何注入自定义反序列化器响应@JsonRawValue外观:

 import com.fasterxml.jackson.databind.Module; @Component public class ModuleImpl extends Module { @Override public void setupModule(SetupContext context) { context.addBeanDeserializerModifier(new BeanDeserializerModifierImpl()); } } 

 import java.util.Iterator; import com.fasterxml.jackson.annotation.JsonRawValue; import com.fasterxml.jackson.databind.BeanDescription; import com.fasterxml.jackson.databind.DeserializationConfig; import com.fasterxml.jackson.databind.deser.BeanDeserializerBuilder; import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier; import com.fasterxml.jackson.databind.deser.SettableBeanProperty; public class BeanDeserializerModifierImpl extends BeanDeserializerModifier { @Override public BeanDeserializerBuilder updateBuilder(DeserializationConfig config, BeanDescription beanDesc, BeanDeserializerBuilder builder) { Iterator<SettableBeanProperty> it = builder.getProperties(); while (it.hasNext()) { SettableBeanProperty p = it.next(); if (p.getAnnotation(JsonRawValue.class) != null) { builder.addOrReplaceProperty(p.withValueDeserializer(KeepAsJsonDeserialzier.INSTANCE), true); } } return builder; } } 

我有完全相同的问题。 我在这篇文章中find了解决scheme: 使用Jackson或其替代方法将JSON树parsing为普通类

看看最后的答案。 通过为将JsonNode作为参数的属性定义一个自定义setter,并调用jsonNode上的toString方法来设置String属性,这一切都可以实现。

这个简单的解决scheme为我工作:

 public class MyObject { private Object rawJsonValue; public Object getRawJsonValue() { return rawJsonValue; } public void setRawJsonValue(Object rawJsonValue) { this.rawJsonValue = rawJsonValue; } } 

所以我能够将原始JSON值存储在rawJsonValuevariables中,然后将其它字段反序列化(作为对象)并将其返回给JSON并通过REST发送。 使用@JsonRawValue没有帮助我,因为存储的JSON反序列化为string,而不是对象,这不是我想要的。

使用一个对象可以很好地工作两种方式…这种方法有两次反序列化原始值的开销。

 ObjectMapper mapper = new ObjectMapper(); RawJsonValue value = new RawJsonValue(); value.setRawValue(new RawHello(){{this.data = "universe...";}}); String json = mapper.writeValueAsString(value); System.out.println(json); RawJsonValue result = mapper.readValue(json, RawJsonValue.class); json = mapper.writeValueAsString(result.getRawValue()); System.out.println(json); RawHello hello = mapper.readValue(json, RawHello.class); System.out.println(hello.data); 

RawHello.java

 public class RawHello { public String data; } 

RawJsonValue.java

 public class RawJsonValue { private Object rawValue; public Object getRawValue() { return rawValue; } public void setRawValue(Object value) { this.rawValue = value; } } 

这甚至适用于JPA实体:

 private String json; @JsonRawValue public String getJson() { return json; } public void setJson(final String json) { this.json = json; } @JsonProperty(value = "json") public void setJsonRaw(JsonNode jsonNode) { setJson(jsonNode.toString()); } 

下面是一个完整的工作示例,说明如何使用Jackson模块使@JsonRawValue工作(序列化和反序列化):

 public class JsonRawValueDeserializerModule extends SimpleModule { public JsonRawValueDeserializerModule() { setDeserializerModifier(new JsonRawValueDeserializerModifier()); } private static class JsonRawValueDeserializerModifier extends BeanDeserializerModifier { @Override public BeanDeserializerBuilder updateBuilder(DeserializationConfig config, BeanDescription beanDesc, BeanDeserializerBuilder builder) { builder.getProperties().forEachRemaining(property -> { if (property.getAnnotation(JsonRawValue.class) != null) { builder.addOrReplaceProperty(property.withValueDeserializer(JsonRawValueDeserializer.INSTANCE), true); } }); return builder; } } private static class JsonRawValueDeserializer extends JsonDeserializer<String> { private static final JsonDeserializer<String> INSTANCE = new JsonRawValueDeserializer(); @Override public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { return p.readValueAsTree().toString(); } } } 

然后你可以在创buildObjectMapper之后注册模块:

 ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new JsonRawValueDeserializerModule()); String json = "{\"foo\":\"one\",\"bar\":{\"A\":false}}"; Pojo deserialized = objectMapper.readValue(json, Pojo.class);