You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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,直接在目标字段上绑定转换逻辑,代码更聚焦:

  1. 导入dart:convert库,用于JSON编解码;
  2. 在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并全局注册:

  1. 定义针对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>();
  }
}
  1. 在全局Serializer中注册这个自定义实现:
@SerializersFor([
  MyResponse,
])
final Serializers _serializers = (_$_serializers.toBuilder()
      ..addPlugin(StandardJsonPlugin())
      ..add(StringifiedListIntSerializer()) // 注册自定义Serializer
    .build();
  1. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 18:18:31