2

我正在尝试使用 reddit JSON API。有些帖子数据对象包含一个名为edited 的字段,如果帖子尚未编辑,则该字段可能包含布尔值 false,如果帖子已编辑,则可能包含时间戳 int。

有时是布尔值:

{
    "edited": false,
    "title": "Title 1"
}

有时是一个整数:

{
    "edited": 1234567890,
    "title": "Title 2"
}

尝试解析 POJO 将字段设置为 int 的 JSON 时,出现错误:JsonDataException: Expected an int but was BOOLEAN ...

我该如何使用 Moshi 处理这个问题?

4

2 回答 2

7

我也遇到了类似的问题,我的字段有时是布尔值,有时是整数。我希望它们始终是整数。以下是我使用 Moshi 和 kotlin 解决的方法:

  1. 创建一个新的注释,你将在字段上使用它应该从布尔值转换为 int

    @JsonQualifier
    @Retention(AnnotationRetention.RUNTIME)
    @Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FUNCTION)
    annotation class ForceToInt

    internal class ForceToIntJsonAdapter {
        @ToJson
        fun toJson(@ForceToInt i: Int): Int {
            return i
        }

        @FromJson
        @ForceToInt
        fun fromJson(reader: JsonReader): Int {
            return when (reader.peek()) {
                JsonReader.Token.NUMBER -> reader.nextInt()
                JsonReader.Token.BOOLEAN -> if (reader.nextBoolean()) 1 else 0
                else -> {
                    reader.skipValue() // or throw
                    0
                }
            }
        }
    }

  1. 在要强制 int 的字段上使用此注释:
    @JsonClass(generateAdapter = true)
    data class Discovery(
            @Json(name = "id") val id: String = -1,
            @ForceToInt @Json(name = "thanked") val thanked: Int = 0
    )
于 2019-08-01T20:43:23.063 回答
1

简单的方法可能是使您的 Javaedited字段成为 Object 类型。性能、错误捕获和应用程序使用的更好方法是使用自定义 JsonAdapter。

示例(根据需要编辑):

public final class Foo {
  public final boolean edited;
  public final int editedNumber;
  public final String title;

  public static final Object JSON_ADAPTER = new Object() {
    final JsonReader.Options options = JsonReader.Options.of("edited", "title");

    @FromJson Foo fromJson(JsonReader reader) throws IOException {
      reader.beginObject();
      boolean edited = true;
      int editedNumber = -1;
      String title = "";
      while (reader.hasNext()) {
        switch (reader.selectName(options)) {
          case 0:
            if (reader.peek() == JsonReader.Token.BOOLEAN) {
              edited = reader.nextBoolean();
            } else {
              editedNumber = reader.nextInt();
            }
            break;
          case 1:
            title = reader.nextString();
            break;
          case -1:
            reader.nextName();
            reader.skipValue();
          default:
            throw new AssertionError();
        }
      }
      reader.endObject();
      return new Foo(edited, editedNumber, title);
    }

    @ToJson void toJson(JsonWriter writer, Foo value) throws IOException {
      writer.beginObject();
      writer.name("edited");
      if (value.edited) {
        writer.value(value.editedNumber);
      } else {
        writer.value(false);
      }
      writer.name("title");
      writer.value(value.title);
      writer.endObject();
    }
  };

  Foo(boolean edited, int editedNumber, String title) {
    this.edited = edited;
    this.editedNumber = editedNumber;
    this.title = title;
  }
}

不要忘记在您的 Moshi 实例上注册适配器。

Moshi moshi = new Moshi.Builder().add(Foo.JSON_ADAPTER).build();
JsonAdapter<Foo> fooAdapter = moshi.adapter(Foo.class);
于 2018-02-23T19:52:25.177 回答