具有枚举值的映射的 Dart json_serializable defaultValue

Posted

技术标签:

【中文标题】具有枚举值的映射的 Dart json_serializable defaultValue【英文标题】:Dart json_serializable defaultValue for Map with Enum Value 【发布时间】:2020-10-15 05:56:39 【问题描述】:

我的主要问题是我想在通过解析 json 创建对象时防止字段值变为 null。 该字段是一个 Map

示例代码:

import 'package:json_annotation/json_annotation.dart';

enum Letter A, B,C
@JsonSerializable()
class example
    @JsonKey(defaultValue: 
        'C': Letter.C
    )
    Map<String, Letter> letters = 
        'A': Letter.A,
        'B':Letter.B
    ;

运行时出错:

flutter pub run build_runner build

错误信息是:

错误运行 JsonSerializableGenerator 错误,@JsonKey on lettersdefaultValueMap &gt; Letter,必须是字面量。

发现这个: https://github.com/google/json_serializable.dart/issues/361

但是如果我尝试使用转换器方法,我会遇到其他问题,因此尝试解决根本问题。

【问题讨论】:

【参考方案1】:

使用枚举的name属性和byName方法

import 'dart:convert';

void main() 
  Person raj = Person(name: 'Raj', favIcecream: Icecream.pista);
  print(raj.toJson());

  Person rajV2 = Person.fromJson(raj.toJson());
  print(rajV2.toJson());

  final isBothInstanceEqual = raj == rajV2;
  print('> Both instancecs are equal is $isBothInstanceEqual');


enum Icecream 
  vanilla,
  pista,
  strawberry,


class Person 
  String name;
  Icecream favIcecream;
  Person(
    required this.name,
    required this.favIcecream,
  );

  Map<String, dynamic> toMap() 
    return 
      'name': name,
      'favIcecream': favIcecream.name, // <- this is how you should save
    ;
  

  factory Person.fromMap(Map<String, dynamic> map) 
    return Person(
      name: map['name'] ?? '',
      favIcecream: Icecream.values.byName(map['favIcecream']), // <- back to enum
    );
  

  String toJson() => json.encode(toMap());

  factory Person.fromJson(String source) => Person.fromMap(json.decode(source));

  @override
  bool operator ==(Object other) 
    if (identical(this, other)) return true;

    return other is Person &&
        other.name == name &&
        other.favIcecream == favIcecream;
  

  @override
  int get hashCode => name.hashCode ^ favIcecream.hashCode;

【讨论】:

【参考方案2】:

适用于最小规模的解决方案。

pupspec.yaml:

name: playground
description: A simple command-line application.

environment:
  sdk: '>=2.8.1 <3.0.0'
dependencies:
  json_annotation: ^3.0.1

dev_dependencies:
  build_runner: ^1.10.0
  json_serializable: ^3.3.0
  pedantic: ^1.9.0

playground.dart:

import 'package:json_annotation/json_annotation.dart';
part 'playground.g.dart';
enum Letter   A,  B,  C
@JsonSerializable()
class example
    example()
    @JsonKey(fromJson: parseMap, toJson: toStringMap)
    Map<String, Letter> letters = 
        'A': Letter.A,
        'B':Letter.B
    ;

    factory example.fromJson(Map<String, dynamic> json) => _$exampleFromJson(json);
    Map<String, dynamic> toJson() => _$exampleToJson(this);

    static Map<String, Letter> parseMap(Map<String,String> m)
      if(m==null)
        return 
          'C': Letter.C
        ;
      
      Map<String, Letter> result =;
      for(String key in m.keys)
         result[key]=Letter.values.firstWhere((e) => e.toString() == m[key]); 
      
      return result;
    
    static Map<String, String> toStringMap(Map<String,Letter> m)
      if(m==null)
        return 
          'C': 'C'
        ;
      
      Map<String, String> result =;
      for(String key in m.keys)
         result[key]=m[key].toString(); 
      
      return result;
    


void main(List<String> arguments) 
  var ex = example.fromJson();
  print(ex.letters.values);
  var ex2 = new example();
  var m =ex2.toJson();
  print(m);
  var ex3 = new example();
  ex3.letters=null;
  var m2 =ex3.toJson();
  print(m2);

运行:

pub run build_runner build
dart .\bin\playground.dart

输出:

(字母.C) 字母:A:Letter.A,B:Letter.B 字母:C:C

【讨论】:

以上是关于具有枚举值的映射的 Dart json_serializable defaultValue的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Dart 中循环枚举

将枚举映射到键或值的类型

具有默认枚举值的枚举类方法失败

具有符合 CaseIterable、RawRepresentable 的关联值的枚举

在 Flutter/Dart 中映射多个列表?

text 具有字符串值的枚举