猿问

Flutter 使用来自 Golang RFC3339 的 DateTime 解析 json:

当尝试读取在 Dart / Flutter 中使用 golangs json 包生成的 json 文件时,我注意到解析日期会产生错误:


FormatException: Invalid date format

一个示例是在 Go 服务器上生成的以下 json:


{

    ...

    "dateCreated": "2018-09-29T19:51:57.4139787-07:00",

    ...

}

我正在使用代码生成方法进行 json(反)序列化,以避免编写所有样板代码。json_serializable 包是可用于此目的的标准包。所以我的代码如下所示:


@JsonSerializable()

class MyObj {


  DateTime dateCreated;


  MyObj( this.dateCreated);


  factory MyObj.fromJson(Map<String, dynamic> json) => _$MyObjFromJson(json);  

  Map<String, dynamic> toJson() => _$MyObjToJson(this); 

}


缥缈止盈
浏览 205回答 2
2回答

米脂

因为文档没有充分涵盖这一点,所以我花了一天时间研究颤动源和不同事物的反复试验来解决它。所以不妨分享一下。Golang 默认情况下在序列化为 Json 时在 RFC3339 中编码 time.Time(如在给定的示例中)。Flutter 明确支持 RFC3339,为什么它不起作用?答案是秒小数部分的支持方式略有不同。虽然 Golang 产生 7 位数字的精度,但 Dart 最多只支持 6 位数字并且不会优雅地处理违规情况。因此,如果将示例更正为只有 6 位精度,它将在 Dart 中解析得很好:{&nbsp; &nbsp; ...&nbsp; &nbsp; "dateCreated": "2018-09-29T19:51:57.413978-07:00",&nbsp; &nbsp; ...}为了以通用的方式解决这个问题,您有两个选择:1. 从字符串中截断额外的精度,或者 2. 实现您自己的解析。假设我们扩展DateTime类并创建您自己的CustomDateTime. 新类重写了parse方法,在将其交给父类的解析方法之前删除 6 位数字后的所有多余部分。现在我们可以在我们的 Dart 类中使用了CustomDateTime。例如:@JsonSerializable()class MyObj {&nbsp; CustomDateTime dateCreated;&nbsp; MyObj( this.dateCreated);&nbsp; factory MyObj.fromJson(Map<String, dynamic> json) => _$MyObjFromJson(json);&nbsp;&nbsp;&nbsp; Map<String, dynamic> toJson() => _$MyObjToJson(this);&nbsp;}但是当然现在代码生成被破坏了,我们得到以下错误:Error running JsonSerializableGeneratorCould not generate 'toJson' code for 'dateCreated'.None of the provided 'TypeHelper' instances support the defined type.幸运的是,该json_annotation软件包现在为我们提供了一个简单的解决方案 - The JsonConverter. 以下是如何在我们的示例中使用它:首先定义一个转换器,向代码生成器解释如何转换我们的CustomDateTime类型:class CustomDateTimeConverter implements JsonConverter<CustomDateTime, String> {&nbsp; const CustomDateTimeConverter();&nbsp; @override&nbsp; CustomDateTime fromJson(String json) =>&nbsp; &nbsp; &nbsp; json == null ? null : CustomDateTime.parse(json);&nbsp; @override&nbsp; String toJson(CustomDateTime object) => object.toIso8601String();}其次,我们只是将此转换器注释为使用我们的 CustomDateTime 数据类型的每个类:@JsonSerializable()@CustomDateTimeConverter()class MyObj {&nbsp; CustomDateTime dateCreated;&nbsp; MyObj( this.dateCreated);&nbsp; factory MyObj.fromJson(Map<String, dynamic> json) => _$MyObjFromJson(json);&nbsp;&nbsp;&nbsp; Map<String, dynamic> toJson() => _$MyObjToJson(this);&nbsp;}这满足了代码生成器和 Voila!我们可以读取带有来自 golang time.Time 的 RFC3339 时间戳的 json。

泛舟湖上清波郎朗

我有同样的问题。我找到了一个非常简单的解决方案。我们可以使用带有 JsonConverter 的自定义转换器。import 'package:json_annotation/json_annotation.dart';class CustomDateTimeConverter implements JsonConverter<DateTime, String> {  const CustomDateTimeConverter();  @override  DateTime fromJson(String json) {    if (json.contains(".")) {      json = json.substring(0, json.length - 1);    }    return DateTime.parse(json);  }  @override  String toJson(DateTime json) => json.toIso8601String();}import 'package:json_annotation/json_annotation.dart';import 'package:my_app/shared/helpers/custom_datetime.dart';part 'publication_document.g.dart';@JsonSerializable()@CustomDateTimeConverter()class PublicationDocument {  final int id;  final int publicationId;  final DateTime publicationDate;  final DateTime createTime;  final DateTime updateTime;  final bool isFree;  PublicationDocument({    this.id,    this.publicationId,    this.publicationDate,    this.createTime,    this.updateTime,    this.isFree,  });  factory PublicationDocument.fromJson(Map<String, dynamic> json) =>      _$PublicationDocumentFromJson(json);  Map<String, dynamic> toJson() => _$PublicationDocumentToJson(this);}
随时随地看视频慕课网APP

相关分类

Go
我要回答