java 接收前如何修改Json体?

t9aqgxwy  于 2023-02-14  发布在  Java
关注(0)|答案(1)|浏览(104)

我从API接收到不同的对象集。每个响应都有以下结构:

items:[
 {
  user_id:1,
  tags: {..}
 },
{..}
]

问题是我不想看到这么无用和不可读的结构,我的意思是,我所有的方法(我使用Retrofit库)都必须有一些next签名:

Call<UserRepresantation>...
Call<RepoRepresentation>...

取而代之

Call<List<Users>>
Call<List<Repos>>

而且我每次都要用到额外的实体:

class UserRepresentation{
  List<Users> items;
}

Retrofite可以使用不同的转换器进行序列化,例如:

Retrofit.Builder()
                .baseUrl(stckUrl)
                .addConverterFactory(GsonConverterFactory.create(new Gson())) < --- converter applying
                .build();

据我所知,我可以使用JsonSeializer来配置这样的行为,但我不知道用什么方式。有人能帮助我解决这个问题吗?
所以,简单来说:
我们有一个response

items:[
 {
  user_id:1,
  tags: {..}
 },
{..}
]

我们需要接收:

List<Users> = gson.fromJson(respose, User.class);
s2j5cfk0

s2j5cfk01#

一种解决方案是编写TypeAdapterFactory,当被要求反序列化任何List<User>List<Repo>时,或者通常对于任何List,该x1e0 f1 a执行解 Package 。然而,这样做的问题是它也适用于这些类型的任何嵌套列表,例如,当您的User类具有字段List<Repo> repos时,那么适配器工厂也将尝试解包其值,并且失败。
因此,一个更可靠的解决方案可能是实现一个TypeAdapterFactory,它跟踪当前是否被用于反序列化顶级值,如果是,则展开/扁平化数据,如果不用于顶级值,则可以简单地让其他注册的适配器工厂处理数据:

class FlatteningTypeAdapterFactory implements TypeAdapterFactory {
    public static final FlatteningTypeAdapterFactory INSTANCE = new FlatteningTypeAdapterFactory();

    private FlatteningTypeAdapterFactory() { }

    /** Tracks whether this is a nested call to this factory */
    private static final ThreadLocal<Boolean> isNestedCall = new ThreadLocal<>();

    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        // Only handle top-level value, for nested calls let other factory handle it
        // Uses Boolean.TRUE.equals to handle case where value is `null`
        if (Boolean.TRUE.equals(isNestedCall.get())) {
            return null;
        }

        TypeAdapter<T> delegate;
        isNestedCall.set(true);
        try {
            delegate = gson.getDelegateAdapter(this, type);
        } finally {
            isNestedCall.remove();
        }

        return new TypeAdapter<T>() {
            @Override
            public void write(JsonWriter out, T value) {
                throw new UnsupportedOperationException();
            }

            @Override
            public T read(JsonReader in) throws IOException {
                in.beginObject();
                String name = in.nextName();
                if (!name.equals("items")) {
                    throw new IllegalArgumentException("Unexpected member name: " + name);
                }

                T value;
                // While using delegate adapter also set isNestedCall in case delegate looks up
                // another adapter dynamically while its `read` method is called
                isNestedCall.set(true);
                try {
                    value = delegate.read(in);
                } finally {
                    isNestedCall.remove();
                }

                in.endObject();
                return value;
            }
        };
    }
}

然后,在构造GsonConverterFactory之前,必须将其注册到GsonBuilder

Gson gson = new GsonBuilder()
    .registerTypeAdapterFactory(FlatteningTypeAdapterFactory.INSTANCE)
    .create();

注意,上面的代码还没有经过广泛的测试;可能存在错误或其不能正确工作的极端情况。

相关问题