简体   繁体   English

将单个JSON元素解析为数组

[英]Parsing single JSON element as array

One of the fields in my JSON response is a String[] when containing more than one element, and a String when it's just one. 我的JSON响应中的一个字段是String [](包含多个元素),而String是一个元素。 Like this: 像这样:

"assets": [
  "0901d196804adc1c",
  "0901d196804ebd93",
  "0901d196804ea5e2"
]

"assets": "0901d196804adc1c"

Ideally, I would like to get a String[] always, so if the JSON type of the element is String, convert it to a String[] with one element. 理想情况下,我总是希望获得String [],因此,如果元素的JSON类型为String,则将其转换为带有一个元素的String []。

How can I do that? 我怎样才能做到这一点?

If you cannot edit the response on the server side: Please refer to this question and answers, looks quite similar to your situation. 如果您无法在服务器端编辑响应:请参考问题和解答,外观与您的情况非常相似。

If you can edit the response, just reply always with String arrays (fe "assets": ["0901d196804adc1c"] ). 如果您可以编辑响应,则始终仅使用String数组(fe "assets": ["0901d196804adc1c"] )进行"assets": ["0901d196804adc1c"]

You have two options: 您有两种选择:

1) Implement custom type adapter for gson to handle such situations (preferable solution). 1)为gson实现自定义类型适配器以处理这种情况(首选解决方案)。

2) Define field of type Object and cast it to the appropriate type at runtime 2)定义对象类型的字段,并在运行时将其强制转换为适当的类型

public static class AssetsContainer{
        private Object assets;

        public List<String> getAssets() {
            if(assets instanceof List<?>) {
                return (List<String>) assets;
            } else if(assets instanceof String){
                return Arrays.asList((String) assets);
            } else {
                //TODO: handle
                return null;
            }
        }
    }

How about using the TypeAdapter API? 如何使用TypeAdapter API?

Gson gson = new GsonBuilder()
    .registerTypeAdapterFactory(SingletonListTypeAdapter.FACTORY)
    .create();

The following will check for non-array JSON types when expecting array types and try to make them into singleton Java Lists. 下面将在期望数组类型时检查非数组JSON类型,并尝试将它们放入单例Java列表中。 (Note that this uses Lists, not arrays. You can adapt it if you want, but Effective Java notes that application-layer code should prefer the Collections APIs over arrays.) (请注意,此方法使用列表,而不使用数组。您可以根据需要对其进行调整,但是有效Java指出,应用程序层代码应该更喜欢Collections API,而不是数组。)

final class SingletonListTypeAdapter<T> extends TypeAdapter<List<T>> {
  static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
    @SuppressWarnings("unchecked")
    @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
      if (type.getRawType() != List.class) {
        return null;
      }
      TypeToken<?> collectionElementType = TypeToken.get(
          getCollectionElementType((ParameterizedType) type.getType()));
      TypeAdapter<List<Object>> delegate = (TypeAdapter<List<Object>>)
          gson.getDelegateAdapter(this, collectionElementType);
      return (TypeAdapter<T>) new SingletonListTypeAdapter<>(delegate);
    }
  };

  private final TypeAdapter<T> delegate;

  SingletonListTypeAdapter(TypeAdapter<T> delegate) {
    this.delegate = delegate;
  }

  @Override public void write(JsonWriter out, List<T> value) throws IOException {
    out.beginArray();
    for (int i = 0, size = value.size(); i < size; i++) {
      delegate.write(out, value.get(i));
    }
    out.endArray();
  }

  @Override public List<T> read(JsonReader in) throws IOException {
    if (in.peek() != BEGIN_ARRAY) {
      return Collections.singletonList(delegate.read(in));
    }
    in.beginArray();
    List<T> expanding = new ArrayList<>();
    while (in.hasNext()) {
      expanding.add(delegate.read(in));
    }
    in.endArray();
    return Collections.unmodifiableList(expanding);
  }

  static Type getCollectionElementType(ParameterizedType type) {
    Type[] types = type.getActualTypeArguments();
    Type paramType = types[0];
    if (paramType instanceof WildcardType) {
      return ((WildcardType) paramType).getUpperBounds()[0];
    }
    return paramType;
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM