基于带有gson的嵌套json对象的父值填充空值

ozxc1zmp  于 2021-07-03  发布在  Java
关注(0)|答案(1)|浏览(499)

我正在反序列化一个json数据结构,如下面的gson示例:

{
  "id": 1,
  "data": [
    {
      "value": 2
    },
    {
      "value": 2
    }
  ]
}

此jsonMap到以下类:

class Element {
   Integer id;
   List<SubElement> data;
   ...
}

class SubElement {
   Integer id;
   Integer value;
   ...
}

我希望能够填补这个领域 idSubElement 基于父对象 id 在反序列化时使用gson的字段。
这样做的意义在于,我在应用程序的多个部分中接收到这种json,例如,我希望ommit这种代码:

child.setId(parent.getId());

我试图实现一个自定义反序列化程序 JsonDeserializer<SubElement> 但是我没有访问根元素的权限,所以无法访问 id .
有什么方法可以进行这种类型的自定义反序列化吗?或者我应该使用 Reflection 比如遍历整个对象寻找感兴趣的字段并相应地更新它?
我正在寻找一个通用的解决方案,它可以对其他嵌套对象有效 id .

lp0sw83n

lp0sw83n1#

有什么方法可以进行这种类型的自定义反序列化吗?
是的,但它不一定需要成为gson反序列化的一部分,除非您希望将该内容集中化。在调用对象的 fromJson 方法(因此不太可靠)。因此,如果您认为gson应该对此负责,您可以将其作为后处理器来实现:

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 :支持类型解析的多类型;反射使用;等。

相关问题