【问题标题】:How to stop Moshi from parsing a specific object attribute如何阻止 Moshi 解析特定对象属性
【发布时间】:2019-08-15 08:37:20
【问题描述】:

我的 JSON 响应(来自服务器)具有 JSON 对象的属性,但我不想全部解析它们,而是希望将其中一些保留为 JSON 编码的字符串。

例如:

{
"date": "23-03-2019",
"changed": true,
"data": {
    "login": "9999999",
    "loginFormatted": "999 99 99",
    }
}

这里我想将“数据”属性解析为字符串。我该怎么做? (我使用的是 Retrofit v2.4.0 和 Moshi v1.5.0)

我的响应模型类:

public class Response {
    @Json(name = "date")
    public long date;
    @Json(name = "changed")
    public boolean changed;
    @Json(name = "data")
    public String data;
}

【问题讨论】:

  • 您是否尝试将 @SerializedName 作为 pojo 中的字符串?
  • @MD 你是说 Gson 吗?
  • 试试@SerializedName("data") String data;
  • @MD 而不是 Moshi,正如你所说,我尝试使用 Gson。但是 java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 46 path $.data 抛出错误

标签: android json retrofit moshi


【解决方案1】:

当 Moshi 查看Response 类的层次结构时,它决定使用JsonAdapter<String> 来解析字段data。所以解决的办法就是告诉Moshi不要使用JsonAdapter<String>来解析它,而是将任务委托给我们的JsonAdapter

谈话很便宜,这是代码。

class KeepAsJsonString {
  public void run() throws Exception {
    String json = "" +
      "{\n" +
      "\"date\": \"23-03-2019\",\n" +
      "\"changed\": true,\n" +
      "\"data\": {\n" +
      "    \"login\": \"9999999\",\n" +
      "    \"loginFormatted\": \"999 99 99\"\n" +
      "    }\n" +
      "}";

    Moshi moshi = new Moshi.Builder().add(new DataToStringAdapter()).build();
    JsonAdapter<Response> jsonAdapter = moshi.adapter(Response.class);

    Response response = jsonAdapter.fromJson(json);
    System.out.println(response.data); // {"login":"9999999","loginFormatted":"999 99 99"}
  }

  static class Response {
    @Json(name = "date")
    public String date;
    @Json(name = "changed")
    public boolean changed;
    // Ask moshi to forward the intermediate result to some function with a String annotated with @DataString,
    // in our case, DataToStringAdapter.fromJson() and DataToStringAdapter.toJson()
    @Json(name = "data")
    public @DataString String data;
  }

  @Retention(RUNTIME)
  @JsonQualifier
  public @interface DataString {
  }

  static class DataToStringAdapter {
    @ToJson
    void toJson(JsonWriter writer, @DataString String string) throws IOException {
      // Write raw JSON string
      writer.value(new Buffer().writeUtf8(string));
    }

    @FromJson @DataString
    String fromJson(JsonReader reader, JsonAdapter<Object> delegate) throws IOException {
      // Now the intermediate data object (a Map) comes here
      Object data = reader.readJsonValue();
      // Just delegate to JsonAdapter<Object>, so we got a JSON string of the object
      return delegate.toJson(data);
    }
  }

  public static void main(String[] args) throws Exception {
    new KeepAsJsonString().run();
  }
}

在 Kotlin 中它可能如下所示:

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

internal class JsonObjectToStringJsonAdapter {

    @ToJson
    fun toJson(@DataString s: String): String {
        return s
    }

    @FromJson
    @DataString
    fun fromJson(reader: JsonReader, adapter: JsonAdapter<Any>): String {
        val jsonObject: Any = reader.readJsonValue()!!
        return adapter.toJson(jsonObject)
    }
}

更新:

正如 Eric Cochran 所提到的,当这个 issue 被修复时,将有一种更有效的方式 (JsonReader.readJsonString()) 将 JSON 读取为字符串。

【讨论】:

  • @ToJson 不会像您预期的那样工作。这当前将写入一个字符串,而不是原始 json。你可能想要writer.value(new Buffer().writeUtf8(string))
  • to fromJson 目前的成本很高。关注github.com/square/moshi/issues/675(以前与此问题同名的问题:github.com/square/moshi/issues/318),了解您想要的真正功能。
  • writer.value(BufferedSource) 在 Moshi 1.6 中可供任何可能使用旧版本并注意到它没有编译的人使用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-07-26
  • 2019-04-20
  • 1970-01-01
  • 2020-01-24
  • 2021-02-03
  • 2022-11-26
  • 2014-03-05
相关资源
最近更新 更多