Ant*_*s42 6 java serialization json gson
我正在尝试为我正在构建的Java(JAX-RS)Web服务实现JSON Merge Patch.
要点是通过将JSON文档发送到仅包含应更改的字段的服务器来完成记录的部分更新.
鉴于此记录
{
"a": "b",
"c": {
"d": "e",
"f": "g"
}
}
Run Code Online (Sandbox Code Playgroud)
,以下JSON更新文档
{
"a":"z",
"c": {
"f": null
}
}
Run Code Online (Sandbox Code Playgroud)
应该为里面设置一个新值"a"
并删除."f"
"c"
后者是问题所在.我不知道如何区分f缺失的输入和f为null的输入.据我所知,两者都将null
在目标Java对象中反序列化.
做什么?
我承认 mlk 的回答,但考虑到我已经有了(并且仍然需要)JSON 对象的 POJO 表示,我觉得自动映射仍然比手动查找更好。
正如我所说,这样做的挑战在于,缺失的 null 值和显式的 null 值在要填充的相应 POJO 中都设置为 nullgson.fromJson(...)
。NULL
(与 R和等不同NA
,Java 只有一种“不存在”的表示形式。)
然而,通过使用Java 8 的Options对我的数据结构进行建模,我可以做到这一点:区分未设置的内容和设置为 的内容null
。这就是我最终得到的结果:
1)我将数据对象中的所有字段替换为Optional<T>
.
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);
}
}
Run Code Online (Sandbox Code Playgroud)
或者嵌套的:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
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();
}
}
Run Code Online (Sandbox Code Playgroud)
3)初始化Gson时注册该适配器。
Gson gsonOptFact = new GsonBuilder()
.serializeNulls() // matter of taste, just for output anyway
.registerTypeAdapterFactory(OptionalTypeAdapter.FACTORY)
.create();
Run Code Online (Sandbox Code Playgroud)
这允许我编写 JSON,以便将 和null
空Optional
序列化为null
(或简单地从输出中删除),同时将 JSON 读入Optional
字段,这样如果该字段是,null
我就知道它在 JSON 输入中丢失,并且如果该字段是我知道它是在输入中Optional.empty
设置的。null
例子:
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])
Run Code Online (Sandbox Code Playgroud)
我认为这将使我能够很好地将 JSON Merge Patch 与我现有的数据对象集成。
归档时间: |
|
查看次数: |
2109 次 |
最近记录: |