AS the javax.json docs suggest the way to create a JsonObject is using the provided builders like:
JsonBuilderFactory factory = Json.createBuilderFactory(config);
JsonObject value = factory.createObjectBuilder()
.add("firstName", "John")
.add("lastName", "Smith")
.add("age", 25)
.add("address", factory.createObjectBuilder()
.add("streetAddress", "21 2nd Street")
.add("city", "New York")
.add("state", "NY")
.add("postalCode", "10021"))
.add("phoneNumber", factory.createArrayBuilder()
.add(factory.createObjectBuilder()
.add("type", "home")
.add("number", "212 555-1234"))
.add(factory.createObjectBuilder()
.add("type", "fax")
.add("number", "646 555-4567")))
.build();
This example adds values for the gives keys. In real life the values are probably derived from some (pojo) domain object like:
JsonBuilderFactory factory = Json.createBuilderFactory(config);
JsonObject value = factory.createObjectBuilder()
.add("firstname", customer.getFirstame())
.add("lastname", customer.getLastame())
.add("age", customer.getAge())
....
The JsonOBjectBuilder throw a NPE in case key or value is null. In case the customer has no registered age then above code will throw a NPE.
So basically for every field I add I have to check if the value is null or not and add the actual value and otherwise do not add the field or add JsonValue.NULL for the key. This causes a lot of (undesired) boilerplate...
In my case I ended up with custom JsonUtils class including various static methods like:
public static void add(JsonObjectBuilder builder, String name, Long value) {
if (value == null) {
builder.add(name, JsonValue.NULL);
}
else {
builder.add(name, value);
}
}
public static void add(JsonObjectBuilder builder, String name, String value) {
if (value == null) {
builder.add(name, JsonValue.NULL);
}
else {
builder.add(name, value);
}
}
and then calling:
builder = Json.createObjectBuilder();
JsonUtils.add(builder, "id", customer.getId());
JsonUtils.add(builder, "name", customer.getName());
JsonUtils.add(builder, "gender", customer.getGender());
builder.build()
But someway if feels not right. Why does the javax.json provide no easier way to add null values (without if else boilerplate) or am I missing something?
My main point of critism against the JSR-353 api is that despite it looks like a really nice fluent api (see top example from apidoc) but in reality it is not.
To include null values in the JSON output of the FOR JSON clause, specify the INCLUDE_NULL_VALUES option. If you don't specify the INCLUDE_NULL_VALUES option, the JSON output doesn't include properties for values that are null in the query results.
The javax. json package provides an Object Model API to process JSON. The Object Model API is a high-level API that provides immutable object models for JSON object and array structures. These JSON structures can be represented as object models using JsonObject and JsonArray interfaces.
It might be difficult to get your JsonObjectBuilder
implementation from the factory but you can make it simpler.
Create a JsonObjectBuilder
decorator class that checks for null
:
public class NullAwareJsonObjectBuilder implements JsonObjectBuilder {
// Use the Factory Pattern to create an instance.
public static JsonObjectBuilder wrap(JsonObjectBuilder builder) {
if (builder == null) {
throw new IllegalArgumentException("Can't wrap nothing.");
}
return new NullAwareJsonObjectBuilder(builder);
}
// Decorated object per Decorator Pattern.
private final JsonObjectBuilder builder;
private NullAwareJsonObjectBuilder(JsonObjectBuilder builder) {
this.builder = builder;
}
public JsonObjectBuilder add(String name, JsonValue value) {
builder.add(name, (value == null) ? JsonValue.NULL : value);
}
// Implement all other JsonObjectBuilder methods.
..
}
And how you to use it:
JsonObjectBuilder builder = NullAwareJsonObjectBuilder.wrap(
factory.createObjectBuilder());
builder.add("firstname", customer.getFirstame())
.add(...
Another possible solution is to use simple and lean helper to wrap a value into JsonValue
object or return JsonValue.NULL
if value is null.
Here is an example:
public final class SafeJson {
private static final String KEY = "1";
//private ctor with exception throwing
public static JsonValue nvl(final String ref) {
if (ref == null) {
return JsonValue.NULL;
}
return Json.createObjectBuilder().add(KEY, ref).build().get(KEY);
}
public static JsonValue nvl(final Integer ref) {
if (ref == null) {
return JsonValue.NULL;
}
return Json.createObjectBuilder().add(KEY, ref).build().get(KEY);
}
public static JsonValue nvl(final java.sql.Date ref) {
if (ref == null) {
return JsonValue.NULL;
}
return Json.createObjectBuilder().add(KEY, ref.getTime()).build().get(KEY);
}
}
Usage is simple:
Json.createObjectBuilder().add("id", this.someId)
.add("zipCode", SafeJson.nvl(this.someNullableInt))
.add("phone", SafeJson.nvl(this.someNullableString))
.add("date", SafeJson.nvl(this.someNullableDate))
.build();
Constructs like Json.createObjectBuilder().add(KEY, ref).build().get(KEY);
looks a little bit weird but it is the only portable way to wrap value into JsonValue
I've found so far.
In fact in JavaEE8 you can replace it with:
Json.createValue()
or underlying:
JsonProvider.provider().createValue()
call.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With