Skip to content

Commit 9143b83

Browse files
authored
Add JsonEnum.valueField for encoding enhanced enum values (#1203)
Fixes #1147 Prepare to release json_annotation v4.7.0
1 parent 572e813 commit 9143b83

File tree

13 files changed

+170
-25
lines changed

13 files changed

+170
-25
lines changed

example/pubspec.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,7 @@ dev_dependencies:
2424
test: ^1.16.0
2525

2626
dependency_overrides:
27+
json_annotation:
28+
path: ../json_annotation
2729
json_serializable:
2830
path: ../json_serializable

json_annotation/CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
## 4.6.1-dev
1+
## 4.7.0
22

3+
- Added `JsonEnum.valueField` which allows specifying a field in an
4+
"enhanced enum" to use for serialization instead of specifying each value
5+
individually with `JsonValue`.
36
- Require Dart SDK 2.17
47

58
## 4.6.0

json_annotation/lib/src/json_enum.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class JsonEnum {
1313
const JsonEnum({
1414
this.alwaysCreate = false,
1515
this.fieldRename = FieldRename.none,
16+
this.valueField,
1617
});
1718

1819
/// If `true`, `_$[enum name]EnumMap` is generated for in library containing
@@ -34,4 +35,11 @@ class JsonEnum {
3435
/// Note: the value for [JsonValue.value] takes precedence over this option
3536
/// for entries annotated with [JsonValue].
3637
final FieldRename fieldRename;
38+
39+
/// Specifies the field within an "enhanced enum" to use as the value
40+
/// to use for serialization.
41+
///
42+
/// If an individual `enum` element is annotated with `@JsonValue`
43+
/// that value still takes precedence.
44+
final String? valueField;
3745
}

json_annotation/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: json_annotation
2-
version: 4.6.1-dev
2+
version: 4.7.0
33
description: >-
44
Classes and helper functions that support JSON code generation via the
55
`json_serializable` package.

json_serializable/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## 6.4.0
2+
3+
- Add support for `JsonEnum.valueField` which allows specifying a field in an
4+
"enhanced enum" to use for serialization instead of specifying each value
5+
individually with `JsonValue
6+
- Require `json_annotation: '>=4.7.0 <4.8.0'`
7+
18
## 6.3.2
29

310
- Require `analyzer: '>=4.6.0 <6.0.0'`

json_serializable/README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -200,14 +200,14 @@ targets:
200200
[`Enum`]: https://api.dart.dev/stable/dart-core/Enum-class.html
201201
[`int`]: https://api.dart.dev/stable/dart-core/int-class.html
202202
[`Iterable`]: https://api.dart.dev/stable/dart-core/Iterable-class.html
203-
[`JsonConverter`]: https://pub.dev/documentation/json_annotation/4.6.0/json_annotation/JsonConverter-class.html
204-
[`JsonEnum`]: https://pub.dev/documentation/json_annotation/4.6.0/json_annotation/JsonEnum-class.html
205-
[`JsonKey.fromJson`]: https://pub.dev/documentation/json_annotation/4.6.0/json_annotation/JsonKey/fromJson.html
206-
[`JsonKey.toJson`]: https://pub.dev/documentation/json_annotation/4.6.0/json_annotation/JsonKey/toJson.html
207-
[`JsonKey`]: https://pub.dev/documentation/json_annotation/4.6.0/json_annotation/JsonKey-class.html
208-
[`JsonLiteral`]: https://pub.dev/documentation/json_annotation/4.6.0/json_annotation/JsonLiteral-class.html
209-
[`JsonSerializable`]: https://pub.dev/documentation/json_annotation/4.6.0/json_annotation/JsonSerializable-class.html
210-
[`JsonValue`]: https://pub.dev/documentation/json_annotation/4.6.0/json_annotation/JsonValue-class.html
203+
[`JsonConverter`]: https://pub.dev/documentation/json_annotation/4.7.0/json_annotation/JsonConverter-class.html
204+
[`JsonEnum`]: https://pub.dev/documentation/json_annotation/4.7.0/json_annotation/JsonEnum-class.html
205+
[`JsonKey.fromJson`]: https://pub.dev/documentation/json_annotation/4.7.0/json_annotation/JsonKey/fromJson.html
206+
[`JsonKey.toJson`]: https://pub.dev/documentation/json_annotation/4.7.0/json_annotation/JsonKey/toJson.html
207+
[`JsonKey`]: https://pub.dev/documentation/json_annotation/4.7.0/json_annotation/JsonKey-class.html
208+
[`JsonLiteral`]: https://pub.dev/documentation/json_annotation/4.7.0/json_annotation/JsonLiteral-class.html
209+
[`JsonSerializable`]: https://pub.dev/documentation/json_annotation/4.7.0/json_annotation/JsonSerializable-class.html
210+
[`JsonValue`]: https://pub.dev/documentation/json_annotation/4.7.0/json_annotation/JsonValue-class.html
211211
[`List`]: https://api.dart.dev/stable/dart-core/List-class.html
212212
[`Map`]: https://api.dart.dev/stable/dart-core/Map-class.html
213213
[`num`]: https://api.dart.dev/stable/dart-core/num-class.html

json_serializable/lib/src/check_dependencies.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import 'package:pubspec_parse/pubspec_parse.dart';
1010

1111
const _productionDirectories = {'lib', 'bin'};
1212
const _annotationPkgName = 'json_annotation';
13-
final requiredJsonAnnotationMinVersion = Version.parse('4.6.0');
13+
final requiredJsonAnnotationMinVersion = Version.parse('4.7.0');
1414

1515
Future<void> pubspecHasRightVersion(BuildStep buildStep) async {
1616
final segments = buildStep.inputId.pathSegments;

json_serializable/lib/src/enum_utils.dart

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,50 @@ String? enumValueMapFromType(
3333

3434
dynamic fieldValue;
3535
if (annotation == null) {
36-
fieldValue = encodedFieldName(jsonEnum.fieldRename, fe.name);
36+
if (jsonEnum.valueField != null) {
37+
// TODO: fieldRename is pointless here!!! At least log a warning!
38+
39+
final fieldElementType = fe.type.element2 as EnumElement;
40+
41+
final e = fieldElementType.getField(jsonEnum.valueField!);
42+
43+
if (e == null || e.isStatic) {
44+
throw InvalidGenerationSourceError(
45+
'`JsonEnum.valueField` was set to "${jsonEnum.valueField}", but '
46+
'that is not a valid, instance field on '
47+
'`${typeToCode(targetType)}`.',
48+
element: targetType.element2,
49+
);
50+
}
51+
52+
final reader = ConstantReader(fe.computeConstantValue());
53+
final valueReader = reader.read(jsonEnum.valueField!);
54+
if (valueReader.validValueType) {
55+
fieldValue = valueReader.literalValue;
56+
} else {
57+
throw InvalidGenerationSourceError(
58+
'`JsonEnum.valueField` was set to "${jsonEnum.valueField}", but '
59+
'that field does not have a type of String, int, or null.',
60+
element: targetType.element2,
61+
);
62+
}
63+
} else {
64+
fieldValue = encodedFieldName(jsonEnum.fieldRename, fe.name);
65+
}
3766
} else {
3867
final reader = ConstantReader(annotation);
3968

4069
final valueReader = reader.read('value');
4170

42-
if (valueReader.isString || valueReader.isNull || valueReader.isInt) {
71+
if (valueReader.validValueType) {
4372
fieldValue = valueReader.literalValue;
4473
} else {
4574
final targetTypeCode = typeToCode(targetType);
4675
throw InvalidGenerationSourceError(
47-
'The `JsonValue` annotation on `$targetTypeCode.${fe.name}` does '
48-
'not have a value of type String, int, or null.',
49-
element: fe);
76+
'The `JsonValue` annotation on `$targetTypeCode.${fe.name}` does '
77+
'not have a value of type String, int, or null.',
78+
element: fe,
79+
);
5080
}
5181
}
5282

@@ -74,10 +104,16 @@ JsonEnum _fromAnnotation(DartObject? dartObject) {
74104
}
75105
final reader = ConstantReader(dartObject);
76106
return JsonEnum(
77-
alwaysCreate: reader.read('alwaysCreate').literalValue as bool,
78-
fieldRename: enumValueForDartObject(
79-
reader.read('fieldRename').objectValue,
80-
FieldRename.values,
81-
(f) => f.toString().split('.')[1],
82-
));
107+
alwaysCreate: reader.read('alwaysCreate').literalValue as bool,
108+
fieldRename: enumValueForDartObject(
109+
reader.read('fieldRename').objectValue,
110+
FieldRename.values,
111+
(f) => f.toString().split('.')[1],
112+
),
113+
valueField: reader.read('valueField').literalValue as String?,
114+
);
115+
}
116+
117+
extension on ConstantReader {
118+
bool get validValueType => isString || isNull || isInt;
83119
}

json_serializable/pubspec.yaml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: json_serializable
2-
version: 6.3.2
2+
version: 6.4.0-dev
33
description: >-
44
Automatically generate code for converting to and from JSON by annotating
55
Dart classes.
@@ -16,7 +16,7 @@ dependencies:
1616

1717
# Use a tight version constraint to ensure that a constraint on
1818
# `json_annotation` properly constrains all features it provides.
19-
json_annotation: '>=4.6.0 <4.7.0'
19+
json_annotation: '>=4.7.0 <4.8.0'
2020
meta: ^1.3.0
2121
path: ^1.8.0
2222
pub_semver: ^2.0.0
@@ -37,3 +37,7 @@ dev_dependencies:
3737
test_descriptor: ^2.0.0
3838
test_process: ^2.0.0
3939
yaml: ^3.0.0
40+
41+
dependency_overrides:
42+
json_annotation:
43+
path: ../json_annotation

json_serializable/test/integration/json_enum_example.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,19 @@ enum DayType {
2525

2626
Iterable<String> get dayTypeEnumValues => _$DayTypeEnumMap.values;
2727

28+
@JsonEnum(alwaysCreate: true, valueField: 'value')
29+
enum MyStatusCode {
30+
success(200),
31+
@JsonValue(701) // explicit value always takes precedence
32+
weird(601);
33+
34+
const MyStatusCode(this.value);
35+
36+
final int value;
37+
}
38+
39+
Iterable<int> get myStatusCodeEnumValues => _$MyStatusCodeEnumMap.values;
40+
2841
@JsonSerializable(
2942
createToJson: false,
3043
)

0 commit comments

Comments
 (0)