JSR-353如何使用javax.json.JsonObjectBuilder添加空值

由于javax.json文档建议创建JsonObject的方法是使用提供的构建器,如:

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

此示例添加了给定键的值。 在现实生活中,这些值可能来自某些(pojo)域对象,如:

 JsonBuilderFactory factory = Json.createBuilderFactory(config); JsonObject value = factory.createObjectBuilder() .add("firstname", customer.getFirstame()) .add("lastname", customer.getLastame()) .add("age", customer.getAge()) .... 

如果key或value为null,则JsonOBjectBuilder抛出NPE。 如果客户没有注册年龄,则上述代码将抛出NPE。

因此,基本上对于我添加的每个字段,我必须检查值是否为null并添加实际值,否则不添加字段或为密钥添加JsonValue.NULL。 这导致很多(不希望的)样板…

在我的情况下,我最终得到了自定义JsonUtils类,包括各种静态方法,如:

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

然后打电话:

 builder = Json.createObjectBuilder(); JsonUtils.add(builder, "id", customer.getId()); JsonUtils.add(builder, "name", customer.getName()); JsonUtils.add(builder, "gender", customer.getGender()); builder.build() 

但是如果感觉不对劲的话。 为什么javax.json没有提供更简单的方法来添加空值(没有if else样板)或者我错过了什么?

我对JSR-353 api的主要批评是,尽管它看起来像一个非常漂亮的流畅 api(参见apidoc的顶级示例),但实际上并非如此。

可能很难从工厂获得JsonObjectBuilder实现,但您可以使其更简单。

创建一个检查nullJsonObjectBuilder装饰器类:

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

以及如何使用它:

 JsonObjectBuilder builder = NullAwareJsonObjectBuilder.wrap( factory.createObjectBuilder()); builder.add("firstname", customer.getFirstame()) .add(... 

另一种可能的解决方案是使用simple和lean helper将值包装到JsonValue对象中,如果value为null,则返回JsonValue.NULL

这是一个例子:

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

用法很简单:

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

构造类似于Json.createObjectBuilder().add(KEY, ref).build().get(KEY); 看起来有点奇怪,但它是唯一可以将值包装到JsonValue我发现到目前为止。

事实上,在JavaEE8中,您可以将其替换为:

 Json.createValue() 

或基础:

 JsonProvider.provider().createValue() 

呼叫。