我尝试将对象转换为JSON。
var obj = { "dt": new DateTime.now() };
var s = stringify(obj);
运行时抛出异常:“在对象上调用toJson方法失败。”
这是预期的,因为DateTime类没有 toJson 方法。 但在这种情况下我该怎么办?
Javascript的JSON.stringify
函数有一个可选参数 replacer ,它允许我提供我自己的任何对象序列化方法,即使该对象没有toJson方法。在Dart中是否有任何类似的工具,或者我可以使用自己的toJson方法以某种方式扩展DateTime类?
答案 0 :(得分:4)
JSON转换仅适用于地图,列表,字符串,数字,布尔值或null。那么,如果您的对象包含另一种类型,例如DateTime
呢?
让我们从以下对象开始:
class Person {
Person(this.name, this.birthdate);
String name;
DateTime birthdate;
}
您可以将其转换为这样的地图:
final person = Person('Bob', DateTime(2020, 2, 25));
Map<String, dynamic> map = {
'name': person.name,
'birthdate': person.birthdate,
};
如果您现在尝试使用jsonEncode
(或json.encode
)对此进行编码,则会由于DateTime
无法直接序列化而出现错误。有两种解决方案。
您可以先自己序列化它:
Map<String, dynamic> map = {
'name': person.name,
'birthdate': person.birthdate.toIso8601String(),
};
final jsonString = json.encode(map);
注意:
这是toString
和toIso8601String
之间的区别:
2020-02-25 14:44:28.534 // toString()
2020-02-25T14:44:28.534 // toIso8601String()
toIso8601String
没有任何空格,因此可以更好地用于转换和通过可能无法很好处理空格的API发送。
您可以在toEncodable
上使用可选的jsonEncode
函数参数。
import 'dart:convert';
void main() {
final person = Person('Bob', DateTime(2020, 2, 25));
Map<String, dynamic> map = {
'name': person.name,
'birthdate': person.birthdate,
};
final toJson = json.encode(map, toEncodable: myDateSerializer);
}
dynamic myDateSerializer(dynamic object) {
if (object is DateTime) {
return object.toIso8601String();
}
return object;
}
toEncodable
函数仅将输入转换为字符串或jsonEncode
可以转换为字符串的内容。
这里没有什么特别的。您只需要将字符串解析为所需的类型即可。对于DateTime
,您可以使用其parse
或tryParse
方法。
final myMap= json.decode(jsonString);
final name = myMap['name'];
final birthdateString = myMap['birthdate'];
final birthdate = DateTime.parse(birthdateString);
final decodedPerson = Person(name, birthdate);
请注意,如果无法将字符串格式解析为parse
对象,则DateTime
将引发异常。
class Person {
Person(this.name, this.birthdate);
String name;
DateTime birthdate;
Person.fromJson(Map<String, dynamic> json)
: name = json['name'],
birthdate = DateTime.tryParse(json['birthdate']),
Map<String, dynamic> toJson() {
return {
'name': name,
'birthdate': birthdate.toIso8601String(),
};
}
}
这不会引发异常,因为日期格式错误,但是birthdate
将是null
。
答案 1 :(得分:3)
Zdeslav Vojkovic的回答现在已经过时了。
JSON.encode()
中的dart:convert
方法有一个可选的toEncodable
方法,该方法可以为不能本机序列化为JSON的对象调用。然后由用户提供一个闭包,返回DateTime的适当序列化。
答案 2 :(得分:1)
IMO,dart:json
库中的一个缺陷stringify
不支持序列化缺少toJson
实现的类型的额外回调。奇怪的是,parse
函数支持reviver
参数来自定义反序列化过程。可能原因在于用户可以为其类型添加toJson
,核心库将处理“本机”类型,但DateTime
被省略(可能是因为JSON中的日期序列化不是真的是一个简单的故事)。
团队的目标可能是使用自定义类型而不是地图(这很好),但这里的缺点是,如果您的自定义类型包含10个其他属性,1个属于DateTime
类型,那么需要实现toJson
,它序列化所有这些,甚至是整数和字符串。希望,一旦Mirror API准备就绪,将会有通过读取类型反射信息来实现序列化“带外”的库,请参阅下面的示例。 Dart的承诺是我可以在服务器和客户端上使用我的类型,但如果我必须为我的所有模型手动实现序列化/反序列化,那么它太难以使用了。
DateTime
本身对格式化不是很灵活也没有用,因为除了toString
之外没有其他方法可以返回格式化无用的格式。
所以这里有一些选择:
DateTime
,提供toJson
json.stringifyJsonValue
并提交更改或至少提交问题:)json-object
这样的第三方派对库(仅作为示例,它也不支持DateTime
序列化,AFAIK 我对他们中的任何一个都不满意:)