generic_enum 0.3.1
generic_enum: ^0.3.1 copied to clipboard
Dart enumerations with extension-methods offering json-serialization and a mapping of each enum instance to a const value with arbitrary data-type.
Generic Enumerations For Dart #
Update #
As of generic_enum 0.3.0 it is not longer required to extend GenericEnum.
In fact, this class has been removed.
The package now uses extension-methods. This change greatly
simplifies the complexity of generic_enum_builder
and reduces the required boiler-plate (generated methods are automatically available).
The added benefit is that standard Dart enums can be made "generic" by mapping each enumeration instance to a constant value of arbitrary data-type.
Introduction #
Enumerations are ideal when we want to model choosing from a limited set of constant values.
In Dart, the value of an enum instance resolves to a String.
The package generic_enum can be used together with
generic_enum_builder to build an extension
supporting json-serialization. Additionally, the values of the enum instances
can be mapped to an arbitrary data-type.
Usage #
To use this library include generic_enum as dependencies in your pubspec.yaml file.
Include generic_enum_builder, and build_runner as dev_dependencies.
The example below shows how to define the enumeration DpiResolution
where the value of each enum instance is mapped to a value of type double.
Click to show source code.
// 0. Import required packages.
import 'package:generic_enum/generic_enum.dart';
import 'package:exception_templates/exception_templates.dart';
// 1. Add a part statement pointing to the generated file.
part 'dpi_resolution.g.dart';
// 2. Define an enumeration.
// and annotate it with @GenerateJsonExtension().
@GenerateJsonExtension()
enum DpiResolution { LOW, MEDIUM, HIGH }
// 3. Define an extension on the enumeration.
extension DpiResolutionValue on DpiResolution {
// 4. Define a getter mapping each instance of the enum to its base value.
double get value => const {
DpiResolution.LOW: 90.0,
DpiResolution.MEDIUM: 300.0,
DpiResolution.HIGH: 600.0,
}[this];
}
-
Add the import directives shown above.
-
Add a part statement referencing the generated file
dpi_resolution.g.dart. -
Define an enumeration and annotate it with @GenerateJsonExtension().
-
Define a public extension on the enumeration.
-
Define a getter mapping each instance of the enum to a unique const value with arbitrary data-type. (Inspired by this issue comment).
-
Configure the build targets (and amend the generate_for entry). In your local
build.yamlfile add configurations for the builderjson_builderprovided by the package generic_enum_builder.Click to show file content.
targets: $default: builders: # Configure the builder `pkg_name|buil, provided by `dart:convert`.der_name` generic_enum_builder|json_builder: # Only run this builder on the specified input. enabled: true generate_for: - lib/*.dartNote: The file
dpi_resolution.dartshould be an asset that can be resolved by the builder. To limit the number of files scanned for annotationed classes during the build process one can use agenerate_forstatement in the builder configuration. -
Build the project by running the command:
$ pub run build_runner build --delete-conflicting-outputs -
For the example presented here, the build process will generate the file
dpi_resolution.g.dart.Click to show file content.
// GENERATED CODE - DO NOT MODIFY BY HAND part of 'dpi_resolution.dart'; // ************************************************************************** // JsonGenerator // ************************************************************************** /// Extension providing the functions `fromJson` and `toJson`. extension ToDpiResolution on DpiResolution { /// Converts [json] to an instance of `DpiResolution`. static DpiResolution fromJson(Map<String, dynamic> json) { final index = (json['index']) as int; if (index == null) { throw ErrorOf<DpiResolution>( message: 'Error deserializing json to DpiResolution.', invalidState: 'json[index] returned null.', expectedState: 'A map entry: {index: int value}.'); } if (index >= 0 && index < DpiResolution.values.length) { return DpiResolution.values[index]; } else { throw ErrorOf<DpiResolution>( message: 'Function fromJson could not find ' 'an instance of type DpiResolution.', invalidState: 'DpiResolution.values[$index] out of bounds.'); } } /// Converts `this` to a map `Map<String, dynamic>`. Map<String, dynamic> toJson() => {'index': DpiResolution.values.indexOf(this)}; /// Converts `this` to a json encoded `String`. String get jsonEncoded => '{"index":${DpiResolution.values.indexOf(this)}}'; }
Limitations #
Because of this issue it is not possible to pass an instance of enum
to the function jsonEncode(Object object) (provided by dart:convert)
even if the function toJson() is defined in an extension of the enum.
Alternative ways to serialize an instance of enum are:
- Use the getter
toJsonEncodedto retrieve a json encodedString. - Pass the result of
toJson()tojsonEncode. - Use a full blown serialization approach like
json_serializable. This is recommended if your project already usesjson_serializable.
When it comes to deserialization, the usual approach is to define a factory constructor named fromJson.
This is not possible since extensions do not support constructors. Moreover, static extension-methods
are accessed by specifying the extension name,
To keep the notation similar to the "usual approach", the extension containing the static method fromJson
is named To + Enum Name, see example below.
import 'dpi_resolution.dart';
import 'package:test/test.dart';
final low = DpiResolution.LOW;
// Encoding:
Map<String, dynamic> json = low.toJson();
// String jsonEncoded0 = jsonEncode(low); Throws! Extensions not available for dynamic types.
String jsonEncoded1 = jsonEncode(json)
String jsonEncoded2 = low.jsonEncoded;
expect(jsonEncode1, jsonEncode2);
// Decoding (notice the prefix "To").
expect(ToDpiResolution.fromJson(json), low);
expect(ToDpiResolution.fromJson(jsonDecode(jsonEncoded)), low);
Examples #
Further examples on how to define and build generic enumeration classes can be found in the package generic_enum_example.
Features and bugs #
Please file feature requests and bugs at the issue tracker.