[Flutter翻译]使用BuiltValueSerializer创建自定义built_value序列化器

微信扫一扫,分享到朋友圈

[Flutter翻译]使用BuiltValueSerializer创建自定义built_value序列化器

原文地址: medium.com/flutter-com…

原文作者: medium.com/@solid.gonc…

发布时间:2019年2月9日 – 3分钟阅读

照片由 Patrick Tomasso on Unsplash 提供。

当使用 built_value 进行JSON序列化和反序列化时,我们可能会遇到一些超出 StandardJsonPlugin 能力的情况。

想象一下下面的问题:你有一个API端点,可以为同一个值提供两种不同类型的数据结构,如下例所示:

{
"value": "String value"
}
复制代码
{
"value": ["String 1", "String 2"]
}
复制代码

在我们的flutter应用中,我们可能希望有一个可以同时拥有这两种值的对象,然后我们决定在我们的Widgets中显示什么。

class CustomValue {
String singleValue;
List<String> multipleValues;
}
复制代码

那么,我们如何将String值映射为 singleValue ,将Strings数组映射为 multiValues 呢?用一个 CustomSerialize

如果我们检查 Serializer 类,就会发现:

must extend either [PrimitiveSerializer] or/
[StructuredSerializer]./
复制代码

由于我们的数据结构不是一个原始对象 我们必须创建一个实现 StructuredSerializer 的类。

class CustomValueSerializer
implements StructuredSerializer<CustomValue> {
@override
CustomValue deserialize(Serializers serializers, Iterable serialized, {FullType specifiedType = FullType.unspecified}) {
// TODO: implement deserialize
return null;
}
@override
Iterable serialize(Serializers serializers, CustomValue object, {FullType specifiedType = FullType.unspecified}) {
// TODO: implement serialize
return null;
}
@override
// TODO: implement types
Iterable<Type> get types => null;
@override
// TODO: implement wireName
String get wireName => null;
}
复制代码

让我们检查一下我们需要实现的每个方法。 types 是可以被序列化的对象的类型。当使用 built_value 时,它会生成一个名为 _$CustomValue 的内部类型,这个类型也必须被序列化,所以我们有:

@override
Iterable<Type> get types => [CustomValue, _$CustomValue];
复制代码

wirename 是我们要序列化的类的名字。

@override
String get wireName => "CustomValue";
复制代码

最后,我们必须实现 serializedeserialize 方法。在这里,我们将能够检查我们接收的值是 String 类型还是 List 类型,并将其映射到 CustomValue 的正确值。要做到这一点,我们需要检查类似类的生成代码是如何结构的,并调整它以适应我们的需求。在这种情况下,我们在检查 value 字段时,并不是直接赋值,而是先检查该变量的属性是哪种类型,将其赋为 String 值或 List<String> 值。 但是,由于我们使用的是 built_value ,我们要处理的List类型来自于 built_collection 包,因此我们要将其声明为 BuiltList<String>

@override
CustomValue deserialize(Serializers serializers, Iterable serialized,
{FullType specifiedType = FullType.unspecified}) {
// Initialize an empty builder
final result = new CustomValueBuilder();
// Create an `Iterator` from the serialized data received
final iterator = serialized.iterator;
// Loop the iterator for each key
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
// for each key, assign the correct value to the builder
switch (key) {
case 'value':
// If the value is of type List<dynamic>, assign it to `values`
if (value is List<dynamic>) {
result.values.replace(serializers.deserialize(value,
specifiedType: const FullType(BuiltList, const [
const FullType(String)
])) as BuiltList);
// else, the value is of type `String`
} else {
result.value = serializers.deserialize(value.toString(),
specifiedType: const FullType(String)) as String;
}
break;
}
}
return result.build();
}
@override
Iterable serialize(Serializers serializers, CustomValue object,
{FullType specifiedType = FullType.unspecified}) {
// Create an empty object array
final result = <Object>[];
// if the value of the `CustomValue` is not null, then assign it to a String
if (object.value != null) {
result
..add('value')
..add(serializers.serialize(object.value,
specifiedType: const FullType(String)));
}
// Else, it means that we have a list. In this case the list will always override
// the defined String value
if (object.values != null) {
result
..add('values')
..add(serializers.serialize(object.values,
specifiedType:
const FullType(BuiltList, const [const FullType(String)])));
}
return result;
}
复制代码

现在,既然我们有了 CustomValueSerializer 类,我们就可以开始研究 CustomValue 类了。

part 'custom_value.g.dart';
abstract class CustomValue implements Built<CustomValue, CustomValueBuilder> {
static Serializer<CustomValue> get serializer => null; // todo
@nullable String get value;
@nullable BuiltList<String> get values;
CustomValue._();
factory CustomValue([updates(CustomValueBuilder b)]) = _$CustomValue;
}
复制代码

该类的设置等于使用 StandardJsonPlugin 的类,唯一不同的是我们声明序列化器的方式。在这种情况下,我们可以使用新的注解 @BuiltValueSerializer 来对序列化器说:”嘿,我们使用的是自定义序列化器,不要为这个类生成一个”

@BuiltValueSerializer(custom: true)
static Serializer<CustomValue> get serializer => CustomDataSerializer();
复制代码

缺少了什么?

我们的 Serializers 类,它声明了项目中所有要序列化的类。对于自定义的序列化器,我们不需要在这个类中添加额外的信息,所以我们可以像通常那样初始化它。

part 'serializers.g.dart';
@SerializersFor(const [
CustomValue
])
Serializers serializers = _$serializers;
Serializers standardSerializers =
(serializers.toBuilder()
..addPlugin(StandardJsonPlugin())
).build();
复制代码

最后,我们可以在终端中运行 build_runner 来生成所有的新文件。

flutter packages pub run build_runner watch

就这样! 我们已经成功地使用了 built_value 的自定义序列器! :tada:

作为奖励,我们可以通过编写一些老式的单元测试来保证一切正常工作。

test("Single value", () {
var value = "test";
var jsonMap = '{"value": "$value"}';
var encodedJson = json.jsonDecode(jsonMap);
CustomValue customValue = standardSerializers.deserializeWith(CustomValue.serializer, encodedJson);
expect(customValue.value, equals(value));
expect(customValue.values, isNull);
});
test("Multiple values", () {
var value1 = "test";
var value2 = "system";
var value = '["$value1", "$value2"]';
var jsonMap = '{"value": $value}';
var encodedJson = json.jsonDecode(jsonMap);
CustomValue customValue = standardSerializers.deserializeWith(CustomValue.serializer, encodedJson);
expect(customValue.value, isNull);
expect(customValue.values, equals([value1, value2]));
});
复制代码

所有测试都通过了,我们就可以开始了。

你可以在 GitHub Repo 中看到完整的例子。

通过www.DeepL.com/Translator(免费版)翻译

微信扫一扫,分享到朋友圈

[Flutter翻译]使用BuiltValueSerializer创建自定义built_value序列化器

关于Babel你需要知道的那些事

上一篇

前端工程化 - 聊聊 Webpack v3 到 Webpack v5 的核心架构变迁

下一篇

你也可能喜欢

[Flutter翻译]使用BuiltValueSerializer创建自定义built_value序列化器

长按储存图像,分享给朋友