根据嵌套 JSON 对象的父值用 Gson 填充空值
Fill empty values based on parent values of nested JSON Object with Gson
我正在使用 GSON 反序列化一个 JSON 数据结构,如下例所示:
{
"id": 1,
"data": [
{
"value": 2
},
{
"value": 2
}
]
}
此 JSON 映射到以下 类:
class Element {
Integer id;
List<SubElement> data;
...
}
class SubElement {
Integer id;
Integer value;
...
}
我希望能够在反序列化时使用 GSON 根据父 id
字段填充 SubElement
对象的字段 id
。
这样做的目的是我在应用程序的几个部分收到了这种 JSON,例如我想省略这种代码:
child.setId(parent.getId());
我尝试实现自定义反序列化器 JsonDeserializer<SubElement>
但我无权访问根元素,因此无法访问 id
.
有什么方法可以进行这种类型的自定义反序列化吗?或者我应该继续使用 Reflection
实施某种解决方案,例如遍历整个对象以寻找感兴趣的领域并相应地更新它?
我正在寻找一种通用解决方案,该解决方案可能适用于缺少 id
的其他嵌套对象。
Is there any way to do this type of custom deserialization?
是的,但它不一定需要成为 Gson 反序列化的一部分,除非您希望它集中化。您始终可以在调用其 fromJson
方法后调整对象(因此不那么可靠)。所以如果你认为 Gson 应该对此负责,你可以将它实现为 post-processor:
public interface IPostProcessorResolver<T> {
@Nullable
Consumer<T> resolvePostProcessor(@Nonnull TypeToken<?> typeToken);
}
public final class PostProcessingTypeAdapterFactory
implements TypeAdapterFactory {
private final IPostProcessorResolver<?> resolvePostProcessor;
private PostProcessingTypeAdapterFactory(final IPostProcessorResolver<?> resolvePostProcessor) {
this.resolvePostProcessor = resolvePostProcessor;
}
public static TypeAdapterFactory create(final IPostProcessorResolver<?> resolvePostProcessor) {
return new PostProcessingTypeAdapterFactory(resolvePostProcessor);
}
@Override
@Nullable
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
@Nullable
@SuppressWarnings("unchecked")
final Consumer<T> postProcessor = (Consumer<T>) resolvePostProcessor.resolvePostProcessor(typeToken);
if ( postProcessor == null ) {
return null;
}
final TypeAdapter<T> delegateTypeAdapter = gson.getDelegateAdapter(this, typeToken);
return new TypeAdapter<T>() {
@Override
public void write(final JsonWriter out, final T value)
throws IOException {
delegateTypeAdapter.write(out, value);
}
@Override
public T read(final JsonReader in)
throws IOException {
// First, read the object
final T object = delegateTypeAdapter.read(in);
// Second, tell it to adjust itself
postProcessor.accept(object);
return object;
}
};
}
}
然后,一个测试:
final Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(PostProcessingTypeAdapterFactory.create((IPostProcessorResolver<Element>) typeToken -> {
if ( typeToken.getRawType() != Element.class ) {
return null;
}
return element -> {
if ( element.data == null ) {
return;
}
for ( @Nullable final SubElement datum : element.data ) {
if ( datum != null ) {
datum.id = element.id;
}
}
};
}))
.create();
...
final Element element = gson.fromJson(jsonReader, Element.class);
Assertions.assertNotNull(element.data);
Assertions.assertEquals(1, (int) element.id);
Assertions.assertEquals(1, (int) element.data.get(0).id);
Assertions.assertEquals(1, (int) element.data.get(1).id);
请注意,您只需实施 IPostProcessorResolver
即可实施更复杂的策略:类型解析支持多种类型;反射使用;等等
我正在使用 GSON 反序列化一个 JSON 数据结构,如下例所示:
{
"id": 1,
"data": [
{
"value": 2
},
{
"value": 2
}
]
}
此 JSON 映射到以下 类:
class Element {
Integer id;
List<SubElement> data;
...
}
class SubElement {
Integer id;
Integer value;
...
}
我希望能够在反序列化时使用 GSON 根据父 id
字段填充 SubElement
对象的字段 id
。
这样做的目的是我在应用程序的几个部分收到了这种 JSON,例如我想省略这种代码:
child.setId(parent.getId());
我尝试实现自定义反序列化器 JsonDeserializer<SubElement>
但我无权访问根元素,因此无法访问 id
.
有什么方法可以进行这种类型的自定义反序列化吗?或者我应该继续使用 Reflection
实施某种解决方案,例如遍历整个对象以寻找感兴趣的领域并相应地更新它?
我正在寻找一种通用解决方案,该解决方案可能适用于缺少 id
的其他嵌套对象。
Is there any way to do this type of custom deserialization?
是的,但它不一定需要成为 Gson 反序列化的一部分,除非您希望它集中化。您始终可以在调用其 fromJson
方法后调整对象(因此不那么可靠)。所以如果你认为 Gson 应该对此负责,你可以将它实现为 post-processor:
public interface IPostProcessorResolver<T> {
@Nullable
Consumer<T> resolvePostProcessor(@Nonnull TypeToken<?> typeToken);
}
public final class PostProcessingTypeAdapterFactory
implements TypeAdapterFactory {
private final IPostProcessorResolver<?> resolvePostProcessor;
private PostProcessingTypeAdapterFactory(final IPostProcessorResolver<?> resolvePostProcessor) {
this.resolvePostProcessor = resolvePostProcessor;
}
public static TypeAdapterFactory create(final IPostProcessorResolver<?> resolvePostProcessor) {
return new PostProcessingTypeAdapterFactory(resolvePostProcessor);
}
@Override
@Nullable
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
@Nullable
@SuppressWarnings("unchecked")
final Consumer<T> postProcessor = (Consumer<T>) resolvePostProcessor.resolvePostProcessor(typeToken);
if ( postProcessor == null ) {
return null;
}
final TypeAdapter<T> delegateTypeAdapter = gson.getDelegateAdapter(this, typeToken);
return new TypeAdapter<T>() {
@Override
public void write(final JsonWriter out, final T value)
throws IOException {
delegateTypeAdapter.write(out, value);
}
@Override
public T read(final JsonReader in)
throws IOException {
// First, read the object
final T object = delegateTypeAdapter.read(in);
// Second, tell it to adjust itself
postProcessor.accept(object);
return object;
}
};
}
}
然后,一个测试:
final Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(PostProcessingTypeAdapterFactory.create((IPostProcessorResolver<Element>) typeToken -> {
if ( typeToken.getRawType() != Element.class ) {
return null;
}
return element -> {
if ( element.data == null ) {
return;
}
for ( @Nullable final SubElement datum : element.data ) {
if ( datum != null ) {
datum.id = element.id;
}
}
};
}))
.create();
...
final Element element = gson.fromJson(jsonReader, Element.class);
Assertions.assertNotNull(element.data);
Assertions.assertEquals(1, (int) element.id);
Assertions.assertEquals(1, (int) element.data.get(0).id);
Assertions.assertEquals(1, (int) element.data.get(1).id);
请注意,您只需实施 IPostProcessorResolver
即可实施更复杂的策略:类型解析支持多种类型;反射使用;等等