Moshi Determine if JSON is array or single object

后端 未结 2 1517
孤街浪徒
孤街浪徒 2021-01-18 07:16

Is there a way to setup a Moshi adapter to automatically create a single Object or List based on the JSON response? Curr
相关标签:
2条回答
  • 2021-01-18 07:23

    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;
    }
    
    0 讨论(0)
  • 2021-01-18 07:40

    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("[]");
    }
    
    0 讨论(0)
提交回复
热议问题