【问题标题】:Gson: Flatten redundant object wrap of an arrayGson:展平数组的冗余对象包装
【发布时间】:2022-01-01 01:18:52
【问题描述】:

我有一种来自服务的数据

  • 服务 A 返回:
{
  "name": "foo",
  "id": 333,
  "contact": [
    {
      "type": "phone",
      "number": "12333333"
    },
    {
      "type": "phone",
      "number": "22333333"
    }
  ]
}
  • 我为它准备了一个模型类:
public class People {
    public String name;
    public int id;
    public List<Contact> contact;

    public static class Contact {
        public String type;
        public String number;
    }
    
}

  • 但服务 B 返回:
{
  "name": "foo",
  "id": 333,
  "contact":{
    "entries": [
      {
        "type": "phone",
        "number": "12333333"
      },
      {
        "type": "phone",
        "number": "22333333"
      }
    ]
  }
}

真实情况是json中有10个list,这个json中的所有list都被一个对象包裹,那么“entries”就是实际的list。 我已经在其他地方使用了模态类,我只想将它们视为同一个类,例如:

Contact contact = people.contact

有什么想法吗?

【问题讨论】:

    标签: java android json gson


    【解决方案1】:

    您可以通过自定义TypeAdapterFactory@JsonAdapter 注释来解决这个问题,这些字段的值可能被包装。

    TypeAdapterFactory 用于获取委托适配器(例如 List&lt;Contact&gt;),然后在必要时创建一个解包 JSON 的适配器。 @JsonAdapter 注解用于将此工厂仅应用于受影响的字段,而不是通常应用于所有 List 值。

    /**
     * Gson {@link TypeAdapterFactory} which unwraps lists inside JSON objects, if
     * necessary.
     * 
     * <p>Must <b>only</b> be used with {@link JsonAdapter @JsonAdapter}.
     */
    public static class WrappedListTypeAdapterFactory implements TypeAdapterFactory {
        // Default constructor to allow Gson to create instances
        public WrappedListTypeAdapterFactory() { }
    
        @Override
        public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
            // Get the actual adapter, for example for `List<Contact>`
            // Note: Cannot use Gson.getDelegateAdapter, see https://github.com/google/gson/issues/1028
            TypeAdapter<T> delegate = gson.getAdapter(type);
    
            return new TypeAdapter<T>() {
                @Override
                public void write(JsonWriter out, T value) throws IOException {
                    delegate.write(out, value);
                }
    
                @Override
                public T read(JsonReader in) throws IOException {
                    JsonToken peeked = in.peek();
                    if (peeked == JsonToken.NULL) {
                        return null;
                    } else if (peeked == JsonToken.BEGIN_ARRAY) {
                        // JSON array is not wrapped, read it directly
                        return delegate.read(in);
                    }
    
                    // Start unwrapping the JSON array
                    in.beginObject();
                    String propertyName = in.nextName();
                    if (!propertyName.equals("entries")) {
                        // Don't include property name to avoid log injection attacks
                        throw new JsonParseException("Unexpected property name");
                    }
    
                    // Now read the JSON array
                    T value = delegate.read(in);
                    in.endObject();
    
                    return value;
                }
            };
        }
    }
    
    public class People {
        public String name;
        public int id;
    
        @JsonAdapter(WrappedListTypeAdapterFactory.class)
        public List<Contact> contact;
    
        public static class Contact {
            public String type;
            public String number;
        }
    }
    

    【讨论】:

    • 非常感谢,这个例子真的让我明白了 TypeAdapterFactory 是如何工作的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-30
    • 2011-07-01
    • 2014-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多