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.
@JsonSetter may help. See my sample ('data' is supposed to contain unparsed JSON):
I had a similar problem, but using a list with a lot of JSON itens (
List<String>
).I managed the serialization using the
@JsonRawValue
annotation. But for deserialization I had to create a custom deserializer based on Roy's suggestion.Below you can see my "List" deserializer.
I had the exact same issue. I found the solution in this post : Parse JSON tree to plain class using Jackson or its alternatives
Check out the last answer. By defining a custom setter for the property that takes a JsonNode as parameter and calls the toString method on the jsonNode to set the String property, it all works out.
Here is a full working example of how to use Jackson modules to make
@JsonRawValue
work both ways (serialization and deserialization):Then you can register the module after creating the
ObjectMapper
:Adding to Roy Truelove's great answer, this is how to inject the custom deserialiser in response to appearance of
@JsonRawValue
:Using an object works fine both ways... This method has a bit of overhead deserializing the raw value in two times.
RawHello.java
RawJsonValue.java