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();
В этом примере добавляются значения для ключей give. В реальной жизни значения, вероятно, получены из некоторого (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 не предоставляет более простого способа добавления нулевых значений (без использования шаблона), или я что-то упустил?
Моя главная точка критики против API JSR-353 заключается в том, что, несмотря на то, что он выглядит как действительно хороший беглый API (см. Лучший пример из Apidoc), но на самом деле это не так.
2 ответа
Это может быть трудно получить ваш 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(...
Другое возможное решение - использовать простой и простой помощник для переноса значения в 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()
вызов.