Skip to content

[Suggestion] Rework Enum management #1538

Open

Description

@EArminjon

Take this example :

import 'package:freezed_annotation/freezed_annotation.dart';

part 'example.g.dart';

enum ExampleType { one, two, three }

@JsonSerializable()
class Example {
  final ExampleType type;
  final String name;

  Example({
    required this.type,
    required this.name,
  });

  factory Example.fromJson(Map<String, dynamic> json) => _$ExampleFromJson(json);

  Map<String, dynamic> toJson() => _$ExampleToJson(this);
}

Once generated we got :

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'example.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

Example _$ExampleFromJson(Map<String, dynamic> json) => Example(
      type: $enumDecode(_$ExampleTypeEnumMap, json['type']),
      name: json['name'] as String,
    );

Map<String, dynamic> _$ExampleToJson(Example instance) => <String, dynamic>{
      'type': _$ExampleTypeEnumMap[instance.type]!,
      'name': instance.name,
    };

const _$ExampleTypeEnumMap = {
  ExampleType.one: 'one',
  ExampleType.two: 'two',
  ExampleType.three: 'three',
};

Json_serializable generates a hard-coded enum ↔ string map in the .g.dart file (e.g. _$ExampleTypeEnumMap). This duplicates information that already exists on the enum itself (Enum.values / Enum.name).

This can be error-prone, especially when the enum comes from an external package (ex: pub.dev, monorepo, ...). If that package updates the enum and build_runner is not re-run, the generated map becomes out of sync with the actual enum definition, potentially leading to errors.

Since enums already expose their values and names, it seems possible to rely on them instead of generating and maintaining a separate hard-coded map.

Activity

  1. lucavenir commented on Jan 7, 2026

    @lucavenir

    Another thing I've noticed is that the following:

    # build.yaml
    targets:
      my_app:
        builders:
          json_serializable:
            options:
              field_rename: snake

    won't apply to enums, and indeed this:

    enum Lol {
      somethingFunny;
    }

    Will result in generated files with a map, e.g.

    Lol.somethingFunny: 'somethingFunny'

    I have to specify @JsonEnum(fieldRename: .snake) explicitly to make this work. On each and every enum.

  2. DinoFive commented on Jul 2, 2026

    @DinoFive

    Consider a enum that has private enum values:

    enum MyEnum {
      a(0),
      b(1),
      _undefined(-1);
    
      final int value;
      const MyEnum(this.value);
    
      static MyEnum fromValue(int value) {
        return MyEnum.values.firstWhere((e) => e.value == value, orElse: () => MyEnum._undefined);
      }
    }
    

    Hard-coded map doesn't work if the enum is defined in another file, since the generated file can not access MyEnum._undefined.
    A custom JsonConverter is needed to handle it:

    class MyEnumJsonConverter implements JsonConverter<MyEnum, String> {
      const MyEnumJsonConverter();
    
      @override
      MyEnum fromJson(String json) => MyEnum.values.firstWhere((e) => e.name == json, orElse: () => MyEnum._undefined);
    
      @override
      String toJson(MyEnum object) => object.name;
    }
    

    Rework enum management as @EArminjon said would make this situation simple.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions