如何使用built_value忽略列表中无需序列化的枚举值?
解决Built JSON反序列化时忽略列表中未定义枚举值的问题
核心问题是服务器返回的text2不在Field枚举的定义范围内,默认的valueOf方法找不到对应枚举会直接抛出异常,导致反序列化失败。可以通过以下两种方式实现忽略无效值:
方案一:自定义枚举序列化器,解析失败时返回null并过滤
- 给
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; }
- 自定义
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); } }
- 修改
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(); } }
- 替换原来的序列化器引用:
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的扩展中添加安全转换方法,然后在反序列化时手动处理列表:
- 添加安全转换扩展:
extension FieldParseExtension on String { Field? toField() { try { return Field.valueOf(this); } catch (_) { return null; } } }
- 在解析服务器返回数据时,先手动过滤无效值再传入
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
相关产品推荐
相关产品推荐

