Skip to content

Commit e303f17

Browse files
committed
feat: implement first version of sealed class serialization
1 parent d30c2fd commit e303f17

File tree

10 files changed

+544
-105
lines changed

10 files changed

+544
-105
lines changed

example/lib/sealed_class_example.dart

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import 'package:json_annotation/json_annotation.dart';
2+
3+
part 'sealed_class_example.g.dart';
4+
5+
@JsonSerializable(
6+
unionDiscriminator: 'runtimeType',
7+
unionRename: UnionRename.snake,
8+
)
9+
sealed class MySealedClass {
10+
MySealedClass(this.value);
11+
12+
factory MySealedClass.fromJson(Map<String, dynamic> json) =>
13+
_$MySealedClassFromJson(json);
14+
15+
String value;
16+
17+
Map<String, dynamic> toJson() => _$MySealedClassToJson(this);
18+
}
19+
20+
@JsonSerializable()
21+
class FirstSubtype extends MySealedClass {
22+
final String someAttribute;
23+
24+
FirstSubtype(
25+
this.someAttribute,
26+
super.value,
27+
);
28+
}
29+
30+
@JsonSerializable()
31+
class SecondSubtype extends MySealedClass {
32+
final String someOtherAttribute;
33+
34+
SecondSubtype(
35+
this.someOtherAttribute,
36+
super.value,
37+
);
38+
}

example/lib/sealed_class_example.g.dart

Lines changed: 53 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

json_annotation/lib/src/allowed_keys_helpers.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,24 @@ class UnrecognizedKeysException extends BadKeyException {
7979
: super._(map);
8080
}
8181

82+
/// Exception thrown if there is an unrecognized union type in a JSON map
83+
/// that was provided during deserialization.
84+
class UnrerecognizedUnionTypeException extends BadKeyException {
85+
/// The discriminator that was not recognized.
86+
final String unrecognizedType;
87+
88+
/// The type of the union that was being deserialized.
89+
final Type unionType;
90+
91+
@override
92+
String get message => 'Unrecognized type: $unrecognizedType '
93+
'for union: $unionType.';
94+
95+
UnrerecognizedUnionTypeException(
96+
this.unrecognizedType, this.unionType, Map map)
97+
: super._(map);
98+
}
99+
82100
/// Exception thrown if there are missing required keys in a JSON map that was
83101
/// provided during deserialization.
84102
class MissingRequiredKeysException extends BadKeyException {

json_annotation/lib/src/json_serializable.dart

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,26 @@ enum FieldRename {
3131
screamingSnake,
3232
}
3333

34+
/// Values for the automatic class renaming behavior for [JsonSerializable]
35+
/// with sealed classes.
36+
enum UnionRename {
37+
/// Use the union class name without changes.
38+
none,
39+
40+
/// Encodes union class named `KebabCase` with a JSON key `kebab-case`.
41+
kebab,
42+
43+
/// Encodes union class named `SnakeCase` with a JSON key `snake_case`.
44+
snake,
45+
46+
/// Encodes union class named `PascalCase` with a JSON key `PascalCase`.
47+
pascal,
48+
49+
/// Encodes union class named `ScreamingSnakeCase` with a JSON key
50+
/// `SCREAMING_SNAKE_CASE`
51+
screamingSnake,
52+
}
53+
3454
/// An annotation used to specify a class to generate code for.
3555
@JsonSerializable(
3656
checked: true,
@@ -162,6 +182,20 @@ class JsonSerializable {
162182
/// fields annotated with [JsonKey].
163183
final FieldRename? fieldRename;
164184

185+
/// Defines the automatic naming strategy when converting class names
186+
/// to union type names.
187+
///
188+
/// With a value [UnionRename.none] (the default), the name of the class is
189+
/// used without modification.
190+
///
191+
/// See [UnionRename] for details on the other options.
192+
final UnionRename? unionRename;
193+
194+
/// The discriminator key used to identify the union type.
195+
///
196+
/// Defaults to `type`.
197+
final String? unionDiscriminator;
198+
165199
/// When `true` on classes with type parameters (generic types), extra
166200
/// "helper" parameters will be generated for `fromJson` and/or `toJson` to
167201
/// support serializing values of those types.
@@ -271,6 +305,8 @@ class JsonSerializable {
271305
this.disallowUnrecognizedKeys,
272306
this.explicitToJson,
273307
this.fieldRename,
308+
this.unionRename,
309+
this.unionDiscriminator,
274310
this.ignoreUnannotated,
275311
this.includeIfNull,
276312
this.converters,
@@ -293,6 +329,8 @@ class JsonSerializable {
293329
disallowUnrecognizedKeys: false,
294330
explicitToJson: false,
295331
fieldRename: FieldRename.none,
332+
unionRename: UnionRename.none,
333+
unionDiscriminator: 'type',
296334
ignoreUnannotated: false,
297335
includeIfNull: true,
298336
genericArgumentFactories: false,
@@ -314,6 +352,8 @@ class JsonSerializable {
314352
disallowUnrecognizedKeys ?? defaults.disallowUnrecognizedKeys,
315353
explicitToJson: explicitToJson ?? defaults.explicitToJson,
316354
fieldRename: fieldRename ?? defaults.fieldRename,
355+
unionRename: unionRename ?? defaults.unionRename,
356+
unionDiscriminator: unionDiscriminator ?? defaults.unionDiscriminator,
317357
ignoreUnannotated: ignoreUnannotated ?? defaults.ignoreUnannotated,
318358
includeIfNull: includeIfNull ?? defaults.includeIfNull,
319359
genericArgumentFactories:

json_annotation/lib/src/json_serializable.g.dart

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)