【问题标题】:How to modify Json body before receiving?接收前如何修改Json body?
【发布时间】:2023-02-14 05:45:06
【问题描述】:

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

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

问题是我不想要如此无用且不可读的结构。 我的意思是,我所有的方法(我使用Retrofit库)都必须有一些下一个签名:

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);

【问题讨论】:

    标签: java json serialization gson


    【解决方案1】:

    一种解决方案是编写一个 TypeAdapterFactory,它在被要求反序列化任何 List&lt;User&gt;List&lt;Repo&gt; 或通常对任何 List 时执行解包。但是,这样做的问题是它也适用于这些类型的任何嵌套列表,例如,当您的 User 类有一个字段 List&lt;Repo&gt; 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();
    

    请注意,上面的代码尚未经过广泛测试;可能存在无法正常工作的错误或极端情况。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-15
      • 2012-06-04
      相关资源
      最近更新 更多