Moshi Determine if JSON is array or single object Moshi Determine if JSON is array or single object json json

Moshi Determine if JSON is array or single object


You can use a JsonQualifier to generalize this.From your example, you might use it like

final class Foo {  @SingleToArray final List<User> users;}

Here's the code with a test to demonstrate more thouroughly.

@Retention(RUNTIME)@JsonQualifier public @interface SingleToArray {  final class Adapter extends JsonAdapter<List<Object>> {    final JsonAdapter<List<Object>> delegateAdapter;    final JsonAdapter<Object> elementAdapter;    public static final Factory FACTORY = new Factory() {      @Nullable @Override      public JsonAdapter<?> create(Type type, Set<? extends Annotation> annotations,          Moshi moshi) {        Set<? extends Annotation> delegateAnnotations =            Types.nextAnnotations(annotations, SingleToArray.class);        if (delegateAnnotations == null) {          return null;        }        if (Types.getRawType(type) != List.class) {          throw new IllegalArgumentException(              "Only lists may be annotated with @SingleToArray. Found: " + type);        }        Type elementType = Types.collectionElementType(type, List.class);        JsonAdapter<List<Object>> delegateAdapter = moshi.adapter(type, delegateAnnotations);        JsonAdapter<Object> elementAdapter = moshi.adapter(elementType);        return new Adapter(delegateAdapter, elementAdapter);      }    };    Adapter(JsonAdapter<List<Object>> delegateAdapter, JsonAdapter<Object> elementAdapter) {      this.delegateAdapter = delegateAdapter;      this.elementAdapter = elementAdapter;    }    @Nullable @Override public List<Object> fromJson(JsonReader reader) throws IOException {      if (reader.peek() != JsonReader.Token.BEGIN_ARRAY) {        return Collections.singletonList(elementAdapter.fromJson(reader));      }      return delegateAdapter.fromJson(reader);    }    @Override public void toJson(JsonWriter writer, @Nullable List<Object> value)        throws IOException {      if (value.size() == 1) {        elementAdapter.toJson(writer, value.get(0));      } else {        delegateAdapter.toJson(writer, value);      }    }  }}@Test public void singleToArray() throws Exception {  Moshi moshi = new Moshi.Builder().add(SingleToArray.Adapter.FACTORY).build();  JsonAdapter<List<String>> adapter =      moshi.adapter(Types.newParameterizedType(List.class, String.class), SingleToArray.class);  assertThat(adapter.fromJson("[\"Tom\",\"Huck\"]")).isEqualTo(Arrays.asList("Tom", "Huck"));  assertThat(adapter.toJson(Arrays.asList("Tom", "Huck"))).isEqualTo("[\"Tom\",\"Huck\"]");  assertThat(adapter.fromJson("\"Jim\"")).isEqualTo(Collections.singletonList("Jim"));  assertThat(adapter.toJson(Collections.singletonList("Jim"))).isEqualTo("\"Jim\"");  assertThat(adapter.fromJson("[]")).isEqualTo(Collections.emptyList());  assertThat(adapter.toJson(Collections.<String>emptyList())).isEqualTo("[]");}


Using @Eric's comment, I came up with the correct code below:

public static <T> List<T> loadFakeData(String url, Class<T> cls){    List<T> list = new ArrayList<>();    Moshi moshi = new Moshi.Builder().build();    try {        JsonReader reader = JsonReader.of(runHttpClient(url));        JsonReader.Token token = reader.peek();        if (token.equals(JsonReader.Token.BEGIN_ARRAY)) {            Type type = Types.newParameterizedType(List.class, cls);            JsonAdapter<List<T>> adapter = moshi.adapter(type);            list = adapter.fromJson(reader);        } else if (token.equals(JsonReader.Token.BEGIN_OBJECT)){            JsonAdapter<T> adapter = moshi.adapter(cls);            T t = adapter.fromJson(reader);            list.add(t);        }    } catch (IOException e) {        e.printStackTrace();    }    return list;}