当尝试读取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);
}
答案 0 :(得分:4)
由于文档不够全面,因此我花了一天的时间研究颤动源以及各种问题的反复试验来解决。因此不妨分享一下。
默认情况下,Golang在序列化为Json时在RFC3339中对time.Time进行编码(如给定示例中所示)。 Flutter明确支持RFC3339,为什么它不起作用?答案是如何支持秒分数部分。虽然Golang产生7位数字的精度,但Dart仅支持最多6位数字,并且不能正常处理违规行为。因此,如果将示例更正为仅具有6位精度,它将在Dart中进行解析:
{
...
"dateCreated": "2018-09-29T19:51:57.413978-07:00",
...
}
为了以一种通用的方式解决这个问题,您有两个选择:1.从字符串中截断附加精度,或者2.实现自己的解析。假设我们扩展DateTime
类并创建自己的CustomDateTime
。新类具有parse
方法,该方法被覆盖以除去6位数字之后的所有多余字符,然后将其交给父类的parse方法。
现在,我们可以在Dart类中使用CustomDateTime
。例如:
@JsonSerializable()
class MyObj {
CustomDateTime dateCreated;
MyObj( this.dateCreated);
factory MyObj.fromJson(Map<String, dynamic> json) => _$MyObjFromJson(json);
Map<String, dynamic> toJson() => _$MyObjToJson(this);
}
但是,当然,现在代码生成已中断,并且出现以下错误:
Error running JsonSerializableGenerator
Could not generate 'toJson' code for 'dateCreated'.
None of the provided 'TypeHelper' instances support the defined type.
幸运的是,json_annotation
软件包现在为我们提供了一个简单的解决方案-JsonConverter
。在我们的示例中,这是使用方法:
首先定义一个转换器,向代码生成器说明如何转换我们的CustomDateTime
类型:
class CustomDateTimeConverter implements JsonConverter<CustomDateTime, String> {
const CustomDateTimeConverter();
@override
CustomDateTime fromJson(String json) =>
json == null ? null : CustomDateTime.parse(json);
@override
String toJson(CustomDateTime object) => object.toIso8601String();
}
第二,我们只是将此转换器注释为使用CustomDateTime数据类型的每个类:
@JsonSerializable()
@CustomDateTimeConverter()
class MyObj {
CustomDateTime dateCreated;
MyObj( this.dateCreated);
factory MyObj.fromJson(Map<String, dynamic> json) => _$MyObjFromJson(json);
Map<String, dynamic> toJson() => _$MyObjToJson(this);
}
这满足了代码生成器和Voila!我们可以使用来自golang time.Time的RFC3339时间戳读取json。
答案 1 :(得分:1)
我遇到了同样的问题。我找到了一个非常简单的解决方案。我们可以在JsonConverter中使用自定义转换器。有关更多说明,请使用我的article。
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);
}