当前位置: 首页 > 知识库问答 >
问题:

使用Enum将映射编码为JSON

郁光熙
2023-03-14

我想将我的Map编码为json。它看起来像这样:

Map<MyEnum, int> map = {type: limit};

其中 MyEnum 是枚举。一个简单的json.encode(map)将不起作用,因为它不知道如何序列化枚举类。

错误消息是:

Unhandled Exception: Converting object to an encodable object failed: _LinkedHashMap len:1

如何将此地图序列化为json?

共有3个答案

曾歌者
2023-03-14

您可以在枚举上创建一个扩展名以将其转换为字符串,然后将地图转换为地图

import 'dart:convert';

enum MyEnum { type }

extension MyEnumModifier on MyEnum {
  String get string => this.toString().split('.').last;
}

void main() {
  Map<MyEnum, int> map = {MyEnum.type: 10};
  Map<String, int> newMap = {};
  
  map.forEach((key, value) =>
    newMap[key.string] = value);
  
  final json = jsonEncode(newMap);
  print(json);
}

输出

{"type":10}

宓季同
2023-03-14

这真的不是一个我会推荐的解决方案,但我最终这么做主要是为了“好玩”。我不保证任何关于解决方案的事情,除了它是可怕的事实。:)

问题是enum没有定义为Json的有效类型,因此整个概念确实给我们带来了一些问题。一种解决方案是将enum值转换为字符串,首先使用enum的名称,然后使用值的名称,如MyFirstEnum.first1。如果对枚举值调用toString(),Dart会给出这种表示。

这很好,但为了安全起见,我们还可以在开头添加一个魔术字符串,如<code>DART_ENUM:MyFirstEnum。first1以便更容易在其他字符串之间识别,这些字符串可能与enumvalue具有相同的名称,而不是enum。

接下来是类型安全。在Json中,我们知道所有的映射都有< code>String作为键的类型。通过制作我们自己的< code>enum表示并允许它也是键,我们不能期望解码器返回例如< code>Map

也就是说,我尝试构建一个Json解码器和编码器来处理< code>enum值。它还适用于地图中的< code>enum键:

import 'dart:convert';

class JsonConverterWithEnumSupport {
  final String magicString;
  final Set<Object> allEnumValues = {};
  final Map<String, Object> enumStringToEnumValue = {};

  JsonConverterWithEnumSupport(List<List<Object>>? enumsValues,
      {this.magicString = "DART_ENUM:"}) {
    enumsValues?.forEach(addEnumValues);
  }

  void addEnumValues(List<Object> enumValues) {
    for (final enumValue in enumValues) {
      enumStringToEnumValue[enumValue.toString()] = enumValue;
      allEnumValues.add(enumValue);
    }
  }

  String _addMagic(dynamic enumValue) => '$magicString$enumValue';
  String _removeMagic(String string) => string.substring(magicString.length);

  String encode(Object? value) =>
      json.encode(value, toEncodable: (dynamic object) {
        if (object is Map) {
          return object.map<dynamic, dynamic>((dynamic key, dynamic value) =>
              MapEntry<dynamic, dynamic>(
                  allEnumValues.contains(key) ? _addMagic(key) : key,
                  allEnumValues.contains(value) ? _addMagic(value) : value));
        }

        if (object is List) {
          return object.map<dynamic>(
              (dynamic e) => allEnumValues.contains(e) ? _addMagic(e) : e);
        }

        if (allEnumValues.contains(object)) {
          return _addMagic(object);
        }

        return object;
      });

  dynamic decode(String source) => json.decode(source, reviver: (key, value) {
        if (value is String && value.startsWith(magicString)) {
          return enumStringToEnumValue[_removeMagic(value)];
        }

        if (value is Map) {
          return value.map<dynamic, dynamic>((dynamic key, dynamic value) =>
              MapEntry<dynamic, dynamic>(
                  (key is String) && key.startsWith(magicString)
                      ? enumStringToEnumValue[_removeMagic(key)]
                      : key,
                  value));
        }

        return value;
      });
}

enum MyFirstEnum { first1, first2 }
enum MySecondEnum { second1, second2 }

void main() {
  final converter =
      JsonConverterWithEnumSupport([MyFirstEnum.values, MySecondEnum.values]);

  final jsonString = converter.encode({
    MyFirstEnum.first1: [MySecondEnum.second2, MySecondEnum.second1],
    'test': {MyFirstEnum.first2: 5}
  });

  print(jsonString);
  // {"DART_ENUM:MyFirstEnum.first1":["DART_ENUM:MySecondEnum.second2","DART_ENUM:MySecondEnum.second1"],"test":{"DART_ENUM:MyFirstEnum.first2":5}}
  print(converter.decode(jsonString));
  // {MyFirstEnum.first1: [MySecondEnum.second2, MySecondEnum.second1], test: {MyFirstEnum.first2: 5}}
}

您将需要输入到 JsonConverter中支持所有可能的枚举值(例如,请参阅底部的方法)。

如果您不希望将魔术字符串附加到每个枚举上,则只需创建带有以下参数的 JsonConverter与以下工具进行支持:魔术字符串:'“作为参数。

欧阳飞章
2023-03-14

你可以在foundation.dart中使用dealEnum方法

 类似资料:
  • 我需要将Java转换为的实例(包括映射内容) 我应该用什么来代替来使此代码可编译?

  • 问题内容: 我有以下JSON表示盐请求的服务器响应: 我尝试使用以下POJO映射它: 现在每次我这样做: 该为空。如何使用Gson将JSON映射到POJO?我的变量顺序对Gson映射重要吗? 问题答案: 我的变量顺序对Gson映射重要吗? 不,不是这样。 如何使用Gson将JSON映射到POJO? 它是 区分大小写 和JSON字符串键应该是相同的POJO类使用的变量名。 您可以使用@Seriali

  • 我有以下JSON来表示salt请求的服务器响应: 我尝试用以下POJO映射它: 每次我这样做: 为空。如何使用GSON将JSON映射到POJO?变量的顺序对Gson映射重要吗?

  • 我知道如何变换

  • 问题内容: 我有一个主枚举类,它本质上是一种对象类型的类定义。例如,它看起来像下面的示例: 我正在尝试建立一个Javascript模型的发布请求,该请求在主体中发送一个映射,例如 到使用 而我得到以下错误信息: 不能建立从字符串“红”型ColorDefinition的地图键:不是一个有效的表示:不能建立从字符串“红”型ColorDefinition的地图键:对于Enum类值不是一个 什么我在这里做

  • 我有4张桌子: 库存(库存ID、可用数量) 一个客户可以有多个订单,而一个订单由多个orderDetails项目组成。我正在尝试将库存项目存储在由库存项目和数量整数组成的映射中。 当我尝试以这种方式持久化它时,第一个库存项目将以1的orderID添加到Order详细信息表中。但是下一个是使用2的orderID插入的(不存在)。 有什么帮助吗?