How to Include Raw JSON in an Object Using Jackson

How can I include raw JSON in an object using Jackson?

@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.

How to parse raw values from JSON array items with Jackson?

You can convert the payload to com.fasterxml.jackson.databind.node.ArrayNode and then iterate through elements (JsonNode in this case) and add them to a List<String> (which you can then convert to String[] if you want).

One thing to be aware of - the formatting will not be as you expect. JsonNode has two methods - toString() which deletes all the white space and toPrettyString which adds whitespaces and newlines to the final String

        String payload = """ 
[
{"a": 1, "b": "hello"},
{"a": 2, "b": "bye"},
"something"
]
""";
ArrayNode items = new ObjectMapper().readValue(payload, ArrayNode.class);

List<String> rawItemsList = new ArrayList<>();

for (JsonNode jsonNode : items) {
rawItemsList.add(jsonNode.toString());
}

// You can just keep using the rawItemsList, but I've converted it to array since the question mentioned it
String[] rawItemsArr = rawItemsList.toArray(new String[0]);

assertEquals("""
{"a":1,"b":"hello"}""", rawItemsArr[0]);
assertEquals("""
{"a":2,"b":"bye"}""", rawItemsArr[1]);
assertEquals("\"something\"", rawItemsArr[2]);

Map nested json to a pojo with raw json value

Jackson is telling you that it can't insert an Object (in the error log) inside a String.

The @JsonRawValue is used during serialization of objects to JSON format. It is a way to indicate that the String field is to be sent as-is. In other words, the purpose is to tell Jackson that the String is a valid JSON and should be sent without escaping or quoting.

What you can do instead is provide Jackson with a custom method for it to set the field value. Using JsonNode as the argument will force Jackson to pass the "raw" value. From there you can get the string representation:

public class ResponseDTO {

private String Id;
private String text;
private String explanation;

//getters and setters;

@JsonProperty("explanation")
private void unpackExplanation(JsonNode explanation) {
this.explanation = explanation.toString();
}
}

How to deserialize raw JSON to Java object with Jackson

With the help of this question mentioned by @Michał Ziober I managed to do it. Posting it here for reference since it was kinda tricky to get it working (with @Value and CamelCase property naming in JSON):

{
"Foo": "some foo",
"Bar": "{ \"bar\": \"some bar\", \"baz\": \"some baz\" }"
}

And the implementation is:

@Value
@Builder
@JsonDeserialize(builder = Foo.FooBuilder.class)
public class Foo {
@JsonAlias("Foo") // note this!
String foo;
Bar bar;

@JsonPOJOBuilder(withPrefix = "")
public static class FooBuilder {
@JsonAlias("Bar") // note this!
@JsonDeserialize(using = BarDeserializer.class)
public FooBuilder bar(Bar bar) {
this.bar = bar;
return this;
}
}
}

@lombok.Value
public class Bar {
String bar;
String baz;
}

public class BarDeserializer extends StdDeserializer<Bar> {
public BarDeserializer() {
super(Bar.class);
}

@Override
public Bar deserialize(JsonParser p, DeserializationContext ctx) throws IOException {
return (Bar) ((ObjectMapper) p.getCodec()).readValue(p.getValueAsString(), _valueClass);
}
}


Related Topics



Leave a reply



Submit