【问题标题】:Moshi Custom Adapter isn't being called未调用 Moshi 自定义适配器
【发布时间】:2018-06-17 00:36:13
【问题描述】:

TL;DR:

我的问题是:

1 - 我如何为"timestamp": 1515375392.225ZonedDateTime 创建一个Adapter

2 - 根据documentationdocumentation,如果我需要moshi对象来获取此适配器,如何在moshi对象Builder中注册List<Report>适配器?


我的 JSON 字符串具有以下结构:

[
  {
    "id": 0,
    "location": {
      "latitude": -22.967049,
      "longitude": -43.19096
    },
    "timestamp": 1515375392.225
  },
  {
    "id": 0,
    "location": {
      "latitude": -22.965845,
      "longitude": -43.191102
    },
    "timestamp": 1515375392.225
  },
.......
}]

timestamp 是由Jackson JavaTimeModule 进行的自动转换,它将ZonedDateTime 转换为timestamp String,以十进制数的形式表示secondsnanoseconds 从一个Instant.

为了解析 JSON timestamp String,我做了以下Moshi 适配器:

public class ZonedDateTimeAdapter {
    @FromJson ZonedDateTime fromJson(String timestamp) {
        int decimalIndex = timestamp.indexOf('.');
        long seconds = Long.parseLong(timestamp.substring(0, decimalIndex));
        long nanoseconds = Long.parseLong(timestamp.substring(decimalIndex));

        return Instant.ofEpochSecond(seconds, nanoseconds).atZone(ZoneId.systemDefault());
    }

    @ToJson String toJson(ZonedDateTime zonedDateTime) {
        Instant instant = zonedDateTime.toInstant();
        return instant.getEpochSecond() + "." + instant.getNano();
    }
}

然后我将此适配器注册为:

Type type = Types.newParameterizedType(List.class, Report.class);

Moshi moshi = new Moshi.Builder().add(new ZonedDateTimeAdapter()).build();
JsonAdapter<List<Report>> reportAdapter = moshi.adapter(type);

retrofit = new Retrofit.Builder()
                       .baseUrl(BASE_URL)
                       .addConverterFactory(MoshiConverterFactory.create(moshi))
                       .build();

问题是,当我使用Retrofit 调用我的网络服务时,我得到以下Exception

com.squareup.moshi.JsonDataException: java.lang.NumberFormatException: 对于输入字符串:".067000000" at $[0].timestamp

(请记住,这里的纳秒 .067000000 与我之前给出的 JSON 示例不同,因为它们在不同时间调用 Web 服务)。

我试图在我的ZonedDateTimeAdapter 上放置一个断点,但它从未被调用过。但它正在影响 Moshi,因为如果我将其从 Moshi.Builder 中删除,错误将变为:

原因:java.lang.IllegalArgumentException:无法序列化 抽象类 org.threeten.bp.ZoneId

我还尝试将ZonedDateTimeAdapter 更改为处理Double 而不是String,但它只是将错误消息更改为:

com.squareup.moshi.JsonDataException: java.lang.NumberFormatException: 对于输入字符串:".515376840747E9" at $[0].timestamp

所以,基本上,我有一堆不断变化的错误消息,不知道我做错了什么。我关注了Custom Adapters 上的 Moshi 文档,但我不知道还能做什么。

【问题讨论】:

  • 这与 Moshi 或 Retrofit 无关。查看堆栈跟踪中的原因,看看哪一行给出了 NumberFormatException。看起来您正在尝试从浮点数解析 Long。
  • 我在我的适配器上放了一个断点,断点永远不会命中。
  • 此外,尽管 JSON 具有浮点数,但 Moshi 文档说 Moshi 会将适配器输入转换为我选择的类型:Note that the method annotated with @FromJson does not need to take a String as an argument. Rather it can take input of any type and Moshi will first parse the JSON to an object of that type and then use the @FromJsonmethod to produce the desired final value. 并且我选择了一个字符串,所以我正在解析来自一个字符串。

标签: android json retrofit2 moshi


【解决方案1】:

您的 JSON 适配器的 @ToJson 方法正在接受一个字符串,但时间戳是一个数字。要么将其更改为数字(即双精度),要么传递 JsonReader 而不是 String 并自己读出数字。在这种情况下,您可以致电reader.nextString()

【讨论】:

  • 我试图做一个双重,正如我在问题中所说,错误变为:com.squareup.moshi.JsonDataException: java.lang.NumberFormatException: For input string: ".515376840747E9" at $[0].timestamp
  • 此外,文档说 Moshi 将 parse the JSON to an object of the type ,这使我得出结论,Moshi 将直接从 JSON 中将值作为字符串提供给我,而不是数字。
  • 有没有可能 Moshi 不能很好地处理一个非常大的 Double?
  • 我最终使用了JsonReader。既不是字符串也不是双重作品,正如我在帖子中所展示的那样,它们都有例外。数字应该能够自动显示为字符串,就像JsonReader 所做的那样。
猜你喜欢
  • 2017-02-08
  • 2017-03-09
  • 2017-03-18
  • 2013-04-21
  • 2021-04-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-26
相关资源
最近更新 更多