我正在尝试为我正在构建的Java(JAX-RS)Web服务实现JSON合并补丁。
要点是通过向服务器发送一个JSON文档来完成记录的部分更新,该文档只包含应该更改的字段。
鉴于此记录
{
"a": "b",
"c": {
"d": "e",
"f": "g"
}
}
,以下JSON更新文档
{
"a":"z",
"c": {
"f": null
}
}
应该为"a"
设置一个新值并删除"c"
中的"f"
。
后者才是问题所在。我不知道如何区分缺少f的输入和f为null的输入。据我所知,这两个都将在目标Java对象中反序列化为null。
做什么?
对于基元类型,请使用可为空的版本。
例如,在通常使用Long的地方使用Long。整数替换int等。
您还可以使用字符串类型来检测丢失的值,但还需要将字符串解析为所需的类型。
我认为您必须使用JsonObject并查看返回的Json对象。
您可以使用JsonParser。解析(java.io.Reader)以获取JsonObject。
我承认mlk的回答,但考虑到我已经(并且仍然需要)JSON对象的POJO表示,我觉得自动映射仍然比手动查找要好。
这样做的挑战是,正如我所说,在gson.fromJson(...)
将填充的相应POJO中,缺失值和显式空值都设置为null。(与例如R的NULL
和NA
不同,Java只有一个表示“不在那里”。)
然而,通过使用Java 8的Optionals对数据结构建模,我可以做到这一点:区分未设置的内容和设置为null的内容。以下是我的结论:
1) 我将html" target="_blank">数据对象中的所有字段替换为可选
public class BasicObjectOptional {
private Optional<String> someKey;
private Optional<Integer> someNumber;
private Optional<String> mayBeNull;
public BasicObjectOptional() {
}
public BasicObjectOptional(boolean initialize) {
if (initialize) {
someKey = Optional.ofNullable("someValue");
someNumber = Optional.ofNullable(42);
mayBeNull = Optional.ofNullable(null);
}
}
@Override
public String toString() {
return String.format("someKey = %s, someNumber = %s, mayBeNull = %s",
someKey, someNumber, mayBeNull);
}
}
或嵌套的:
public class ComplexObjectOptional {
Optional<String> theTitle;
Optional<List<Optional<String>>> stringArray;
Optional<BasicObjectOptional> theObject;
public ComplexObjectOptional() {
}
public ComplexObjectOptional(boolean initialize) {
if (initialize) {
theTitle = Optional.ofNullable("Complex Object");
stringArray = Optional.ofNullable(Arrays.asList(Optional.ofNullable("Hello"),Optional.ofNullable("World")));
theObject = Optional.ofNullable(new BasicObjectOptional(true));
}
}
@Override
public String toString() {
return String.format("theTitle = %s, stringArray = %s, theObject = (%s)", theTitle, stringArray, theObject);
}
}
2) 基于这个有用的SO答案实现了序列化器和反序列化器。
public class OptionalTypeAdapter<E> extends TypeAdapter<Optional<E>> {
public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
//@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
Class<T> rawType = (Class<T>) type.getRawType();
if (rawType != Optional.class) {
return null;
}
final ParameterizedType parameterizedType = (ParameterizedType) type.getType();
final Type actualType = parameterizedType.getActualTypeArguments()[0];
final TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(actualType));
return new OptionalTypeAdapter(adapter);
}
};
private final TypeAdapter<E> adapter;
public OptionalTypeAdapter(TypeAdapter<E> adapter) {
this.adapter = adapter;
}
@Override
public void write(JsonWriter out, Optional<E> value) throws IOException {
if(value == null || !value.isPresent()){
out.nullValue();
} else {
adapter.write(out, value.get());
}
}
@Override
public Optional<E> read(JsonReader in) throws IOException {
final JsonToken peek = in.peek();
if(peek != JsonToken.NULL){
return Optional.ofNullable(adapter.read(in));
}
in.nextNull();
return Optional.empty();
}
}
3) 初始化Gson时注册了此适配器。
Gson gsonOptFact = new GsonBuilder()
.serializeNulls() // matter of taste, just for output anyway
.registerTypeAdapterFactory(OptionalTypeAdapter.FACTORY)
.create();
这允许我编写JSON,这样一来,null
和empty可选都被序列化为null
(或简单地从输出中删除),同时将JSON读取到可选
字段中,这样,如果该字段是null
,我知道JSON输入中缺少该字段,如果该字段是可选的。空
我知道它在输入中被设置为空。
例子:
System.out.println(gsonOptFact.toJson(new BasicObjectOptional(true)));
// {"someKey":"someValue","someNumber":42,"mayBeNull":null}
System.out.println(gsonOptFact.toJson(new ComplexObjectOptional(true)));
// {"theTitle":"Complex Object","stringArray":["Hello","World"],"theObject":{"someKey":"someValue","someNumber":42,"mayBeNull":null}}
// Now read back in:
String basic = "{\"someKey\":\"someValue\",\"someNumber\":42,\"mayBeNull\":null}";
String complex = "{\"theTitle\":\"Complex Object\",\"stringArray\":[\"Hello\",\"world\"],\"theObject\":{\"someKey\":\"someValue\",\"someNumber\":42,\"mayBeNull\":null}}";
String complexMissing = "{\"theTitle\":\"Complex Object\",\"theObject\":{\"someKey\":\"someValue\",\"mayBeNull\":null}}";
BasicObjectOptional boo = gsonOptFact.fromJson(basic, BasicObjectOptional.class);
System.out.println(boo);
// someKey = Optional[someValue], someNumber = Optional[42], mayBeNull = Optional.empty
ComplexObjectOptional coo = gsonOptFact.fromJson(complex, ComplexObjectOptional.class);
System.out.println(coo);
// theTitle = Optional[Complex Object], stringArray = Optional[[Optional[Hello], Optional[world]]], theObject = (Optional[someKey = Optional[someValue], someNumber = Optional[42], mayBeNull = Optional.empty])
ComplexObjectOptional coom = gsonOptFact.fromJson(complexMissing, ComplexObjectOptional.class);
System.out.println(coom);
// theTitle = Optional[Complex Object], stringArray = null, theObject = (Optional[someKey = Optional[someValue], someNumber = null, mayBeNull = Optional.empty])
我认为这将允许我将JSON合并补丁与现有数据对象很好地集成。
首先,我想说这是一个大学项目。 我有三节课<代码>订单抽象类和从订单继承的和类。 我使用Gson序列化/反序列化子类,但我遇到了一点问题。订单类有一个字段,gson使用该字段来确定订单类型,DineIn或Delivery。 序列化工作得很好。问题是,每当我尝试反序列化时,类型字段值都不会读取,并且总是设置为null,即使它存在于JSON文件中。当有很多字段时,就会发生这种情况,因为当我尝试在较小的
我有一个Java对象,我想序列化为JSON。但是,在此之前,我为该对象的字段设置了一些属性。现在我想将这个对象序列化为JSON。如何仅序列化显式赋值的字段,而基本上排除所有其他字段? 对我来说,在对象类上添加这些注释是不起作用的:和。原因是我有一些基本数据类型的字段。通过添加上述两个注释之一,我并没有阻止原始数据类型字段被序列化。例如,我有几个布尔字段,它们将被序列化为默认值。但是,我不希望这些字
我想序列化特定字段或类的空值。 在GSON中,选项适用于整个JSON。 例子: 使用GSON创建JSON: 电流输出: 期望输出: 如何达到预期的输出? 首选解决方案应具有以下特性: 默认情况下不要序列化空值 为具有特定注释的字段序列化空值。
我试图使用Gson自定义序列化将以下类序列化为Json。
我正在尝试为接受JSON输入的前端库创建一个java SDK。本质上,此SDK将特定类型的对象转换为JSON,然后由前端库使用。 我正在使用杰克逊的多态序列化/反序列化使用它的注释系统。 我有一个基类a和扩展a的两个子类B和C。类a有一个类型字段,我用它来决定要使用哪个类(B或C)。语法如下所示: 现在,当我使用Jackson的ObjectMapper函数读取字符串化的JSON并转换为类A时,我根
我正在努力用本地化反序列化世界天气在线API结果。 是否有更好、更简单的解决方案,只为lang对象编写一个自定义反序列化器,并允许GSON自动反序列化其余数据?