如何在built_value中处理字段的JSON字符串序列化与反序列化?
问题
我有一个API返回如下TypeScript类型:
type Response = { id: string; values: Stringified<number[]>, // 实际是JSON字符串 }
其中type Stringified<T> = string;,也就是通过jsonEncode得到的字符串。我想用Dart的built_value库创建匹配该响应结构的Built类,现有代码如下:
@SerializersFor([ MyResponse, ]) final Serializers _serializers = (_$_serializers.toBuilder() ..addPlugin(StandardJsonPlugin()) .build(); abstract class MyResponse implements Built<MyResponse, MyResponseBuilder> { factory MyResponse([void Function(MyResponseBuilder) updates]) = _$MyResponse; MyResponse._(); Map<String, dynamic> toJson() { return _serializers.serializeWith(MyResponse.serializer, this)! as Map<String, dynamic>; } static MyResponse fromJson(Map<String, dynamic> json) { return _serializers.deserializeWith(MyResponse.serializer, json)!; } static Serializer<MyResponse> get serializer => _$myResponseSerializer; String get id; List<int> get values; }
当前代码适配的JSON格式是:
{ "id": "id", "values": [0, 1, 2] }
但实际API接收/发送的JSON格式是:
{ "id": "id", "values": "[0, 1, 2]" }
请问如何覆写values字段的toJson/fromJson逻辑,或者添加转换管道,在JSON序列化/反序列化时自动执行jsonEncode/jsonDecode?
解决方案
方法一:字段级自定义序列化/反序列化函数
这种方式无需修改全局Serializer,直接在目标字段上绑定转换逻辑,代码更聚焦:
- 导入
dart:convert库,用于JSON编解码; - 在
values字段上添加@BuiltValueField注解,指定序列化和反序列化函数:
修改后的完整代码:
import 'dart:convert'; import 'package:built_value/built_value.dart'; import 'package:built_value/serializer.dart'; @SerializersFor([ MyResponse, ]) final Serializers _serializers = (_$_serializers.toBuilder() ..addPlugin(StandardJsonPlugin()) .build(); abstract class MyResponse implements Built<MyResponse, MyResponseBuilder> { factory MyResponse([void Function(MyResponseBuilder) updates]) = _$MyResponse; MyResponse._(); Map<String, dynamic> toJson() { return _serializers.serializeWith(MyResponse.serializer, this)! as Map<String, dynamic>; } static MyResponse fromJson(Map<String, dynamic> json) { return _serializers.deserializeWith(MyResponse.serializer, json)!; } static Serializer<MyResponse> get serializer => _$myResponseSerializer; String get id; // 绑定字段的自定义转换逻辑 @BuiltValueField( serialize: _serializeValues, deserialize: _deserializeValues, ) List<int> get values; } // 反序列化:JSON字符串转List<int> List<int> _deserializeValues(String value) { return (jsonDecode(value) as List).cast<int>(); } // 序列化:List<int>转JSON字符串 String _serializeValues(List<int> value) { return jsonEncode(value); }
方法二:全局自定义Serializer(多类复用场景)
如果多个类都有类似的JSON字符串化数组字段,可以创建通用Serializer并全局注册:
- 定义针对
List<int>的自定义Serializer:
class StringifiedListIntSerializer implements PrimitiveSerializer<List<int>> { @override final Iterable<Type> types = const [List<int>]; @override final String wireName = 'StringifiedListInt'; @override Object serialize(Serializers serializers, List<int> object, {FullType specifiedType = FullType.unspecified}) { return jsonEncode(object); } @override List<int> deserialize(Serializers serializers, Object serialized, {FullType specifiedType = FullType.unspecified}) { return (jsonDecode(serialized as String) as List).cast<int>(); } }
- 在全局Serializer中注册这个自定义实现:
@SerializersFor([ MyResponse, ]) final Serializers _serializers = (_$_serializers.toBuilder() ..addPlugin(StandardJsonPlugin()) ..add(StringifiedListIntSerializer()) // 注册自定义Serializer .build();
- 在
MyResponse的values字段上指定使用该Serializer:
abstract class MyResponse implements Built<MyResponse, MyResponseBuilder> { // ... 其他代码不变 ... @BuiltValueField(wireName: 'values', serializer: StringifiedListIntSerializer()) List<int> get values; }
两种方案都能实现需求:反序列化时自动将JSON字符串转为List<int>,序列化时自动将List<int>转为JSON字符串。优先推荐方法一,逻辑更清晰且无需全局配置。
内容的提问来源于stack exchange,提问作者Valentin Vignal
相关产品推荐
相关产品推荐

