Dart中JSON序列化和反序列化的现状

3

我在C#上进行序列化方面的经验很好,在搜索和测试了一些Dart库之后,我感到通常并没有真正令人满意的答案。

  1. 我想知道Dart中JSON序列化/反序列化的当前状态是什么?
  2. 我们应该期待未来会有什么改进吗?
  3. 这最终会得到语言本身的支持吗?
  4. 目前最佳实践是什么?

我也希望任何阅读此内容的人都能发布任何新信息,即使帖子变旧。


“Serialization/Deserialization of JSON in Dart” 是什么意思? - Robert
这取决于您的需求。 - Günter Zöchbauer
JSON的序列化很简单 - JSON是一种文本格式。我猜你想要将Dart对象序列化为JSON,并从JSON反序列化。这就引出了一个问题:为什么序列化格式很重要呢?Dart具有“类JSON”数据(num、string、bool、null、List和Map<String,?>)的JSON编码,但JSON编码不是序列化。有序列化库,但它们可能没有基于JSON的序列化格式(好吧,一个字符串将是JSON,但这可能不是你想要的)。 - lrn
7个回答

4

目前,最好的选择可能是使用Smoke库。

它是Mirrors功能的一个子集,但具有基于Mirrors和基于Codegen的实现。它由PolymerDart团队编写,因此它是我们能够获得的“官方”最接近的东西。

在开发过程中,它将使用基于Mirrors的编码/解码;但是对于发布,您可以创建一个小型转换器来生成代码。

Seth Ladd创建了这里的代码示例,我稍微扩展了一下以支持子对象:

abstract class Serializable {
  static fromJson(Type t, Map json) {
    var typeMirror = reflectType(t);
    T obj = typeMirror.newInstance(new Symbol(""), const[]).reflectee;
    json.forEach((k, v) {
      if (v is Map) {
        var d = smoke.getDeclaration(t, smoke.nameToSymbol(k));
        smoke.write(obj, smoke.nameToSymbol(k), Serializable.fromJson(d.type, v));
      } else {
        smoke.write(obj, smoke.nameToSymbol(k), v);
      }
    });
    return obj;
  }

  Map toJson() {
    var options = new smoke.QueryOptions(includeProperties: false);
    var res = smoke.query(runtimeType, options);
    var map = {};
    res.forEach((r) => map[smoke.symbolToName(r.name)] = smoke.read(this, r.name));
    return map;
  }
}

目前,在Smoke中没有支持获取通用类型信息(例如支持List)的功能;然而,我在这里提出了一个问题:

https://code.google.com/p/dart/issues/detail?id=20584

在此问题得到解决之前,实现您想要的“好”实现并不是真正可行的;但我希望它很快就会被实现;因为进行基本的JSON序列化有点依赖于它!

Alan Knight也正在开发一个序列化包,但我发现它缺乏对将日期时间转换为字符串等简单事物的支持,并且解决方案似乎过于冗长,而这些都是非常基本的。

目前,在我的项目中,我选择使用代码生成我们的JSON序列化(以toMap和fromMap方法的形式),因为我们已经有了服务器端的C#版本。如果时间允许,我想整理这些代码并制作一个NuGet包(它支持嵌套对象、数组、排除属性等)。


只要没有循环,子对象是否也可以有子对象? - Cristian Garcia
基于代码生成的实现在大多数情况下并不适用,因为这需要进行代码转换,这不是最佳决策。 - mezoni
在Smoke中?还是我的C#中?我的C#可以处理任意数量的级别,它只是用于从/到映射,并使用内置的JSON编码器,尽管我不确定它如何处理循环。 - Danny Tuppeny

3
我知道这是一个老问题了,但如果你在2019年及以后的时间里访问这里,我发现有一个非常出色的代码生成解决方案:https://pub.dartlang.org/packages/json_serializable。从 Git-hub 代码库来看,我认为这也是“官方”解决方案。 它使用注释 @JsonSerializable@JsonKey 来控制序列化。 在我的经验中,它似乎可以完美地处理继承等问题。当您构建项目时,它会自动生成序列化和反序列化函数。

2

目前,您可以使用redstone_mapper将Dart对象和JSON之间进行转换。这个包是Redstone.dart框架的一个插件,但也可以在没有该框架的情况下使用。此外,还有其他选项可在Pub上获得。


它是否可以序列化/反序列化嵌套对象? - Cristian Garcia
是的,可以。您还可以使用嵌套列表和映射。 - luizmineo

1

你最好的选择是什么? - Cristian Garcia

1
一般来说,人们越来越倾向于使用基于代码生成(codegen)而非基于镜像(mirrors)的解决方案,特别是基于 package:source_gen。这是因为 codegen 可提供比 mirrors 更小、更快的运行时性能。
一个使用 codegen 进行序列化的包是 built_value:

https://github.com/google/built_value.dart

使用built_value,您的模型类如下所示:
abstract class Account implements Built<Account, AccountBuilder> {
  static Serializer<Account> get serializer => _$accountSerializer;

  int get id;
  String get name;
  BuiltMap<String, JsonObject> get keyValues;

  factory Account([updates(AccountBuilder b)]) = _$Account;
  Account._();
}

请注意,built_value不仅涉及序列化 -- 它还提供了operator==、hashCode、toString和一个builder类。


0

我目前正在使用可导出进行序列化,并使用变形进行反序列化。


0
Dart有一个实现来编码和解码Maps、Lists和原始类型的功能。你可以在这篇文章中找到例子。如果你想要速度,这可能是最快的,因为它们实现了本地C/C++的json转换-作者制作的库通常是用Dart编写的,速度会更慢。 JSON.encodeJSON.decode的缺点是除了上述提到的对象之外,它们不能接受任何其他对象,而没有toJson和fromJson方法。
幸运的是,有一些库利用Dart中的反射使其更容易。我自己做了一个小型的库,可以将对象序列化和反序列化为JSON,而不需要额外的代码来处理你的类。你可以在这里找到它。除了上述解决方案,还有很多你可以在Dart pub网站上找到。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接