原文地址:medium.com/flutter-com…git
原文做者:medium.com/@solid.gonc…github
发布时间:2019年2月9日 - 3分钟阅读shell
照片由Patrick Tomasso on Unsplash提供。json
当使用built_value进行JSON序列化和反序列化时,咱们可能会遇到一些超出StandardJsonPlugin
能力的状况。数组
想象一下下面的问题:你有一个API端点,能够为同一个值提供两种不一样类型的数据结构,以下例所示:markdown
{ "value": "String value" } 复制代码
{ "value": ["String 1", "String 2"] } 复制代码
在咱们的flutter应用中,咱们可能但愿有一个能够同时拥有这两种值的对象,而后咱们决定在咱们的Widgets中显示什么。数据结构
class CustomValue { String singleValue; List<String> multipleValues; } 复制代码
那么,咱们如何将String值映射为singleValue
,将Strings数组映射为multiValues
呢?用一个CustomSerialize
。ide
若是咱们检查Serializer类,就会发现:oop
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"; 复制代码
最后,咱们必须实现serialize
和deserialize
方法。在这里,咱们将可以检查咱们接收的值是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的自定义序列器! 🎉
做为奖励,咱们能够经过编写一些老式的单元测试来保证一切正常工做。
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(免费版)翻译