Casual JSON generation with Jackson

aka POJOs are optional

As most Java developers know, Jackson is a very powerful library for converting between Plain Old Java Objects (POJOs) and various data formats, most notably JSON. By defining Java object — and especially with optional annotations — you can construct elaborate data structures to match almost any use case.
There is quite a bit of documentation showing how to do that; for example:

But while useful and often convenient, you do not really HAVE TO define Java classes write or read JSON with Jackson: for “casual” usage there are simple alternatives. Let’s have a look at such POJO-less approach.

Use Collections, Maps, for writing JSON

ObjectMapper mapper = new JsonMapper(); // needed for all useString json = mapper.writeValueAsString(Collections.singletonMap(
"message", "Hello, world!"); // {"message":"Hello, world!"}
String json2 = mapper.writeValueAsString(Arrays.asList(true,
137, "stuff"); // [true,137,stuff];
// can combine as well
String json3 = mapper.writeValueAsString(Collections.singletonMap(
"props", Collections.singletonMap("id", 37)));
// {"props":{"id":37}}

So you can just create Maps and Collections/arrays with names/values that you want and write them out.

For more convenience — at least for Map case (for JSON Arrays, Arrays.asList() is fine), you may want to use either Guava (if on Java 8), or Java 9 Map.of(...) for multiple entries case:

String json = mapper.writeValueAsString(ImmutableMap.of(
"id", 3,
"name", "Bob",
"props", ImmutableMap.of(
"type" : "A-25",
"rate" : 37.25
)
));
// {"id":3,"name":"Bob","props":{"type":"A-25","rate":37.25}}

and so forth. You can nest Map/Collection/array values easily as well.
Example above used just simple scalar types (numbers, Strings, booleans).

Actually, not just Collection/Map/array types

byte[] imageData = Encoder.encode(image); // from some external src
String json = mapper.writeValueAsString(Map.of(
"data" : imageData, // binary data encoded as base64
"type" : ImageType.JPEG, // enums handled just fine
"createdAt" : ZonedDateTime.now(), // as long as Java 8 date/time module registered
));
// {"data":"WRabGC=","type":"JPEG","createdAt":"2021-01-25T18:00:01.0003Z"}

but even more, you can mix and match:

  • POJOs you might have
  • JsonNode (tree model values)
  • Even pre-encoded JSON (with RawValue)

The last one might be of interest sometimes, when embedding already encoded JSON:

String innerJson = mapper.writeValueAsString(
Collections.singletonMap("id", "A-137"));
String combined = mapper.writeValueAsString(Arrays.asList(
"properties", new RawValue(innerJson));
// -> ["properties",{"id":"A-137"}]

Still quite configurable, too

String prettyJson = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(Map.of("msg", "hello!"));

and similarly you can use alternate settings for various SerializationFeature s, StreamWriteFeatures, JsonWriteFeatures and so on:

// Write date/time values as Strings, not numeric timestamps;
// also force escaping (quoting) of non-ASCII characters:
mapper.writer()
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.enable(JsonWriteFeature.ESCAPE_NON_ASCII)
.writeValueAsString(...);

so simple does not mean limited.

May also consider Tree Model (JsonNode)

ObjectNode root = mapper.createObjectNode();
root.put("message", "Hello, world!");
root.put("id", 137);
String json = mapper.writeValueAsString();
// Or, if default settings are ok, these work too
String json2 = root.toString();
String prettyJson = root.toPrettyString();

Also related: Jackson-jr

Open Source developer, most known for Jackson data processor (nee “JSON library”), author of many, many other OSS libraries for Java, from ClassMate to Woodstox

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store