处理一个有时是布尔值的字段,有时是int

时间:2018-02-22 03:05:26

标签: moshi

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

有时是布尔值:

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

有时候是一个int: { "edited": 1234567890, "title": "Title 2" }

当试图解析POJO将字段设置为int的JSON时,我收到一个错误:JsonDataException:期望一个int但是BOOLEAN ...

我如何使用Moshi来解决这个问题?

2 个答案:

答案 0 :(得分:2)

我也遇到了类似的问题,其中我的字段有时是布尔值,有时是整数。我希望他们永远是整数。这是我用Moshi和Kotlin解决的方法:

  1. 制作新的注释,以将其用于将字段从boolean转换为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. 在您要强制整数的字段上使用此注释:
    @JsonClass(generateAdapter = true)
    data class Discovery(
            @Json(name = "id") val id: String = -1,
            @ForceToInt @Json(name = "thanked") val thanked: Int = 0
    )

答案 1 :(得分:1)

简单的方法可能是使您的Java edited字段成为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);