JSR-353如何使用javax.json.JsonObjectBuilder添加空值
正如javax.json文档所建议的那样,创建JsonObject的方法是使用提供的构建器,如:JSR-353如何使用javax.json.JsonObjectBuilder添加空值,java,json,jakarta-ee,glassfish,jsr-353,Java,Json,Jakarta Ee,Glassfish,Jsr 353,正如javax.json文档所建议的那样,创建JsonObject的方法是使用提供的构建器,如: JsonBuilderFactory factory = Json.createBuilderFactory(config); JsonObject value = factory.createObjectBuilder() .add("firstName", "John") .add("lastName", "Smith") .add("age", 25)
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())
....
如果键或值为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-353API的主要批评是,尽管它看起来像一个非常好的fluentapi(参见apidoc中的顶级示例),但实际上它不是。从工厂获得
JsonObjectBuilder
实现可能很困难,但您可以简化它
创建一个检查null
的JsonObjectBuilder
装饰器类:
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(...
另一种可能的解决方案是使用简单而精简的帮助程序将值包装到
JsonValue
对象中,或者如果值为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()
打电话。有趣的主意。我想知道是否有可能更进一步,让工厂自己返回一个NullAwareJsonObjectBuilder?我曾尝试使用ServiceLoader提供我自己的JsonProviderImpl,但扩展glassfish类并不是一个真正的选项。几乎所有方便的字段和方法都是私有的,因此最终都会复制所有内容。。。效果很好。在实现方法的过程中,我学到了一些要点。首先,您需要一个返回类型(在大多数情况下,返回该类型;对于build()情况,返回builder.build()。其次,其中包含JsonValue.NULL的三元运算符不适用于其他方法签名。我最终得到了一个简单的条件if(arg1==null){builder.addNull(arg0);}else{builder.add(arg0,arg1);}我发现这样的东西不属于默认实现,令人难以置信。有什么好的理由吗?确实有几十个比JSR-353更好的选择;那么也许看看,比如说,小杰克逊()?它有真正流畅的API(“编写器”),不像JSON-P有更多的“差不多”版本。