Skip to content
Open
3 changes: 3 additions & 0 deletions json_annotation/.idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions json_annotation/.idea/json_annotation.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions json_annotation/.idea/libraries/Dart_Packages.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions json_annotation/.idea/libraries/Dart_SDK.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions json_annotation/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions json_annotation/.idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions json_annotation/.idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 20 additions & 2 deletions json_annotation/lib/src/enum_helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@

import 'json_key.dart';

/// Compare an enum value against a source using case-insensitive.
///
/// Exposed only for code generated by `package:json_serializable`.
/// Not meant to be used directly by user code.
bool $enumCompareCaseInsensitive(String arg1, Object arg2) => arg2 is String &&
(arg1.toLowerCase() == arg2.toLowerCase());

/// Compare an enum value against a source.
///
/// Exposed only for code generated by `package:json_serializable`.
/// Not meant to be used directly by user code.
bool $enumCompareStandard<V>(V arg1, Object arg2) => arg1 == arg2;

/// Returns the key associated with value [source] from [enumValues], if one
/// exists.
///
Expand All @@ -18,13 +31,16 @@ K? $enumDecodeNullable<K extends Enum, V>(
Map<K, V> enumValues,
Object? source, {
Enum? unknownValue,
bool Function(V arg1, Object arg2)? comparator,
}) {
if (source == null) {
return null;
}

comparator ??= $enumCompareStandard;

for (var entry in enumValues.entries) {
if (entry.value == source) {
if (comparator(entry.value, source)) {
return entry.key;
}
}
Expand Down Expand Up @@ -65,6 +81,7 @@ K $enumDecode<K extends Enum, V>(
Map<K, V> enumValues,
Object? source, {
K? unknownValue,
bool Function(V arg1, Object arg2)? comparator,
}) {
if (source == null) {
throw ArgumentError(
Expand All @@ -73,8 +90,9 @@ K $enumDecode<K extends Enum, V>(
);
}

comparator ??= $enumCompareStandard;
for (var entry in enumValues.entries) {
if (entry.value == source) {
if (comparator(entry.value, source)) {
return entry.key;
}
}
Expand Down
7 changes: 7 additions & 0 deletions json_annotation/lib/src/json_enum.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class JsonEnum {
const JsonEnum({
this.alwaysCreate = false,
this.fieldRename = FieldRename.none,
this.caseInsensitive = false,
this.valueField,
});

Expand All @@ -36,6 +37,12 @@ class JsonEnum {
/// for entries annotated with [JsonValue].
final FieldRename fieldRename;

/// If `true`, enum comparison will be done using case-insensitive.
///
/// The default, `false`, means enum comparison will be done using
/// case-sensitive.
final bool caseInsensitive;

/// Specifies the field within an "enhanced enum" to use as the value
/// to use for serialization.
///
Expand Down
7 changes: 6 additions & 1 deletion json_serializable/lib/src/enum_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,12 @@ JsonEnum _fromAnnotation(DartObject? dartObject) {
final reader = ConstantReader(dartObject);
return JsonEnum(
alwaysCreate: reader.read('alwaysCreate').literalValue as bool,
fieldRename: readEnum(reader.read('fieldRename'), FieldRename.values)!,
caseInsensitive: reader.read('caseInsensitive').literalValue as bool,
fieldRename: enumValueForDartObject(
reader.read('fieldRename').objectValue,
FieldRename.values,
(f) => f.toString().split('.')[1],
),
valueField: reader.read('valueField').literalValue as String?,
);
}
Expand Down
6 changes: 6 additions & 0 deletions json_serializable/lib/src/json_key_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,14 @@ KeyConfig _from(FieldElement element, ClassConfig classAnnotation) {
final ctorParamDefault = classAnnotation.ctorParamDefaults[element.name];

if (obj.isNull) {
final enumObj = jsonEnumAnnotation(element);

return _populateJsonKey(
classAnnotation,
element,
defaultValue: ctorParamDefault,
caseInsensitive: enumObj.isNull ? null :
enumObj.read('caseInsensitive').literalValue as bool?,
includeFromJson: classAnnotation.ignoreUnannotated ? false : null,
includeToJson: classAnnotation.ignoreUnannotated ? false : null,
);
Expand Down Expand Up @@ -286,6 +290,7 @@ KeyConfig _populateJsonKey(
String? readValueFunctionName,
bool? required,
String? unknownEnumValue,
bool? caseInsensitive,
bool? includeToJson,
bool? includeFromJson,
}) {
Expand All @@ -307,6 +312,7 @@ KeyConfig _populateJsonKey(
readValueFunctionName: readValueFunctionName,
required: required ?? false,
unknownEnumValue: unknownEnumValue,
caseInsensitive: caseInsensitive,
includeFromJson: includeFromJson,
includeToJson: includeToJson,
);
Expand Down
3 changes: 3 additions & 0 deletions json_serializable/lib/src/type_helpers/config_types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ class KeyConfig {

final String? unknownEnumValue;

final bool? caseInsensitive;

final String? readValueFunctionName;

KeyConfig({
Expand All @@ -35,6 +37,7 @@ class KeyConfig {
required this.readValueFunctionName,
required this.required,
required this.unknownEnumValue,
required this.caseInsensitive,
});
}

Expand Down
2 changes: 2 additions & 0 deletions json_serializable/lib/src/type_helpers/enum_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ class EnumHelper extends TypeHelper<TypeHelperContextWithConfig> {
expression,
if (jsonKey.unknownEnumValue != null)
'unknownValue: ${jsonKey.unknownEnumValue}',
if ((jsonKey.caseInsensitive ?? false) == true)
r'comparator: $enumCompareCaseInsensitive',
];

return '$functionName(${args.join(', ')})';
Expand Down
10 changes: 10 additions & 0 deletions json_serializable/lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import 'type_helpers/config_types.dart';

const _jsonKeyChecker = TypeChecker.fromRuntime(JsonKey);

const _jsonEnumChecker = TypeChecker.fromRuntime(JsonEnum);

DartObject? _jsonKeyAnnotation(FieldElement element) =>
_jsonKeyChecker.firstAnnotationOf(element) ??
(element.getter == null
Expand All @@ -22,6 +24,14 @@ DartObject? _jsonKeyAnnotation(FieldElement element) =>
ConstantReader jsonKeyAnnotation(FieldElement element) =>
ConstantReader(_jsonKeyAnnotation(element));

DartObject? _jsonEnumAnnotation(Element? element) =>
(element != null && element is ClassElement) ?
_jsonEnumChecker.firstAnnotationOf(element)
: null;

ConstantReader jsonEnumAnnotation(FieldElement element) =>
ConstantReader(_jsonEnumAnnotation(element.type.element));

/// Returns `true` if [element] is annotated with [JsonKey].
bool hasJsonKeyAnnotation(FieldElement element) =>
_jsonKeyAnnotation(element) != null;
Expand Down
6 changes: 6 additions & 0 deletions json_serializable/test/integration/integration_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ void main() {
roundTripOrder(order);
});

test('case insensitive map', () {
final jsonOrder = {'category': 'CHaRmED'};
final order = Order.fromJson(jsonOrder);
expect(order.category, Category.charmed);
});

test('required, but missing enum value fails', () {
expect(
() => Person.fromJson({
Expand Down
2 changes: 1 addition & 1 deletion json_serializable/test/integration/json_test_common.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'dart:collection';

import 'package:json_annotation/json_annotation.dart';

@JsonEnum(fieldRename: FieldRename.kebab)
@JsonEnum(fieldRename: FieldRename.kebab, caseInsensitive: true)
enum Category {
top,
bottom,
Expand Down