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

如何使用built_value忽略列表中无需序列化的枚举值?

解决Built JSON反序列化时忽略列表中未定义枚举值的问题

核心问题是服务器返回的text2不在Field枚举的定义范围内,默认的valueOf方法找不到对应枚举会直接抛出异常,导致反序列化失败。可以通过以下两种方式实现忽略无效值:

方案一:自定义枚举序列化器,解析失败时返回null并过滤

  1. 给Field类添加安全解析方法,避免抛出异常:
class Field extends EnumClass {
  const Field._(String name) : super(name);

  static BuiltSet<Field> get values => _$values;
  // 自定义安全解析方法,找不到对应枚举返回null
  static Field? safeValueOf(String name) {
    return values.firstWhere((e) => e.name == name, orElse: () => null);
  }

  static Serializer<Field> get serializer => _$fieldSerializer;

  static const Field text1 = _$text1;
}
  1. 自定义Field的序列化器,使用安全解析:
class SafeFieldSerializer implements Serializer<Field> {
  @override
  Iterable<Type> get types => const [Field];

  @override
  String get wireName => 'Field';

  @override
  Object serialize(Serializers serializers, Field object, {FullType specifiedType = FullType.unspecified}) {
    return object.stringValue;
  }

  @override
  Field? deserialize(Serializers serializers, Object serialized, {FullType specifiedType = FullType.unspecified}) {
    final String value = serialized as String;
    return Field.safeValueOf(value);
  }
}
  1. 修改Fields的序列化器,过滤列表中的null值:
class FieldsSerializer implements StructuredSerializer<Fields> {
  @override
  Iterable<Type> get types => const [Fields, _$Fields];

  @override
  String get wireName => 'Fields';

  @override
  Iterable<Object?> serialize(Serializers serializers, Fields object, {FullType specifiedType = FullType.unspecified}) {
    return [
      'list1',
      serializers.serialize(object.list1, specifiedType: const FullType(BuiltList, [FullType(Field)])),
    ];
  }

  @override
  Fields deserialize(Serializers serializers, Iterable<Object?> serialized, {FullType specifiedType = FullType.unspecified}) {
    final builder = FieldsBuilder();
    final iterator = serialized.iterator;
    
    while (iterator.moveNext()) {
      final key = iterator.current as String;
      iterator.moveNext();
      final value = iterator.current;

      if (key == 'list1' && value != null) {
        final rawList = value as List<dynamic>;
        // 过滤掉解析失败的null值
        final validFields = rawList
            .map((item) => serializers.deserialize(item, specifiedType: const FullType(Field)))
            .whereType<Field>()
            .toList();
        builder.list1.replace(validFields);
      }
    }

    return builder.build();
  }
}
  1. 替换原来的序列化器引用:
abstract class Fields implements Built<Fields, FieldsBuilder> {
  factory Fields([void Function(FieldsBuilder) updates]) = _$Fields;

  Fields._();

  // 使用自定义的序列化器
  static Serializer<Fields> get serializer => FieldsSerializer();

  BuiltList<Field> get list1;
}

方案二:修改枚举解析逻辑,直接忽略未知值(更简洁)

如果不想自定义整个序列化器,可以在Field的扩展中添加安全转换方法,然后在反序列化时手动处理列表:

  1. 添加安全转换扩展:
extension FieldParseExtension on String {
  Field? toField() {
    try {
      return Field.valueOf(this);
    } catch (_) {
      return null;
    }
  }
}
  1. 在解析服务器返回数据时,先手动过滤无效值再传入Fields构造:
// 假设服务器返回的原始数据是map
final rawData = await fetchData();
final rawList = rawData['list1'] as List<dynamic>;
final validFields = rawList
    .map((item) => (item as String).toField())
    .whereType<Field>()
    .toList();

final fields = Fields((b) => b..list1.replace(validFields));

这种方式适合不需要全局修改序列化逻辑的场景,直接在数据解析层处理。

内容的提问来源于stack exchange,提问作者kmtz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 13:15:41