18

由于 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())
     ....

如果键或值为空,JsonOBjectBuilder 会抛出 NPE。如果客户没有注册年龄,那么上面的代码将抛出 NPE。

所以基本上对于我添加的每个字段,我都必须检查值是否为空并添加实际值,否则不要添加字段或为键添加 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 的顶级示例),但实际上并非如此。

4

2 回答 2

14

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

创建一个JsonObjectBuilder装饰器类来检查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.
    ..
}

以及如何使用它:

JsonObjectBuilder builder = NullAwareJsonObjectBuilder.wrap(
        factory.createObjectBuilder());
builder.add("firstname", customer.getFirstame())
    .add(...
于 2014-03-13T08:38:54.667 回答
2

另一种可能的解决方案是使用简单而精益的助手将值包装到JsonValue对象中,或者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()

称呼。

于 2017-10-11T18:51:32.217 回答