diff --git a/json_annotation/lib/src/json_serializable.dart b/json_annotation/lib/src/json_serializable.dart index 34fe2abb6..13be3af4a 100644 --- a/json_annotation/lib/src/json_serializable.dart +++ b/json_annotation/lib/src/json_serializable.dart @@ -64,6 +64,13 @@ class JsonSerializable { /// This setting has no effect if [createFactory] is `false`. final String? constructor; + /// If `true` (defaults to false), a private, static `_$ExampleJsonMeta` + /// constant is created in the generated part file. + /// + /// This constant can be used by other code-generators to support features + /// such as [fieldRename]. + final bool? createJsonMeta; + /// If `true` (the default), a private, static `_$ExampleFromJson` method /// is created in the generated part file. /// @@ -231,6 +238,7 @@ class JsonSerializable { this.anyMap, this.checked, this.constructor, + this.createJsonMeta, this.createFactory, this.createToJson, this.disallowUnrecognizedKeys, diff --git a/json_serializable/lib/src/encoder_helper.dart b/json_serializable/lib/src/encoder_helper.dart index fd963329d..71b7a2a84 100644 --- a/json_serializable/lib/src/encoder_helper.dart +++ b/json_serializable/lib/src/encoder_helper.dart @@ -16,6 +16,26 @@ import 'unsupported_type_error.dart'; abstract class EncodeHelper implements HelperCore { String _fieldAccess(FieldElement field) => '$_toJsonParamName.${field.name}'; + /// Generates an object containing metadatas related to the encoding, + /// destined to be used by other code-generators. + String createJsonMeta(Set accessibleFieldSet) { + assert(config.createJsonMeta); + + final buffer = + StringBuffer('const _\$${element.name}JsonMeta = {'); + + for (final field in accessibleFieldSet) { + buffer.writeln( + '${escapeDartString(field.name)}: ' + '${escapeDartString(nameAccess(field))},', + ); + } + + buffer.write('};'); + + return buffer.toString(); + } + Iterable createToJson(Set accessibleFields) sync* { assert(config.createToJson); diff --git a/json_serializable/lib/src/generator_helper.dart b/json_serializable/lib/src/generator_helper.dart index 011fd46d3..ecf8bb22d 100644 --- a/json_serializable/lib/src/generator_helper.dart +++ b/json_serializable/lib/src/generator_helper.dart @@ -108,6 +108,10 @@ class GeneratorHelper extends HelperCore with EncodeHelper, DecodeHelper { }, ); + if (config.createJsonMeta) { + yield createJsonMeta(accessibleFieldSet); + } + if (config.createToJson) { yield* createToJson(accessibleFieldSet); } diff --git a/json_serializable/lib/src/type_helpers/config_types.dart b/json_serializable/lib/src/type_helpers/config_types.dart index 6d51ac475..34357a6cc 100644 --- a/json_serializable/lib/src/type_helpers/config_types.dart +++ b/json_serializable/lib/src/type_helpers/config_types.dart @@ -45,6 +45,7 @@ class ClassConfig { final String constructor; final bool createFactory; final bool createToJson; + final bool createJsonMeta; final bool disallowUnrecognizedKeys; final bool explicitToJson; final FieldRename fieldRename; @@ -60,6 +61,7 @@ class ClassConfig { required this.constructor, required this.createFactory, required this.createToJson, + required this.createJsonMeta, required this.disallowUnrecognizedKeys, required this.explicitToJson, required this.fieldRename, @@ -76,6 +78,8 @@ class ClassConfig { checked: config.checked ?? ClassConfig.defaults.checked, anyMap: config.anyMap ?? ClassConfig.defaults.anyMap, constructor: config.constructor ?? ClassConfig.defaults.constructor, + createJsonMeta: + config.createJsonMeta ?? ClassConfig.defaults.createJsonMeta, createFactory: config.createFactory ?? ClassConfig.defaults.createFactory, createToJson: config.createToJson ?? ClassConfig.defaults.createToJson, @@ -101,6 +105,7 @@ class ClassConfig { constructor: '', createFactory: true, createToJson: true, + createJsonMeta: false, disallowUnrecognizedKeys: false, explicitToJson: false, fieldRename: FieldRename.none, @@ -115,6 +120,7 @@ class ClassConfig { constructor: constructor, createFactory: createFactory, createToJson: createToJson, + createJsonMeta: createJsonMeta, ignoreUnannotated: ignoreUnannotated, explicitToJson: explicitToJson, includeIfNull: includeIfNull, diff --git a/json_serializable/lib/src/utils.dart b/json_serializable/lib/src/utils.dart index 470627491..1bcc645c2 100644 --- a/json_serializable/lib/src/utils.dart +++ b/json_serializable/lib/src/utils.dart @@ -56,6 +56,7 @@ JsonSerializable _valueForAnnotation(ConstantReader reader) => JsonSerializable( constructor: reader.read('constructor').literalValue as String?, createFactory: reader.read('createFactory').literalValue as bool?, createToJson: reader.read('createToJson').literalValue as bool?, + createJsonMeta: reader.read('createJsonMeta').literalValue as bool?, disallowUnrecognizedKeys: reader.read('disallowUnrecognizedKeys').literalValue as bool?, explicitToJson: reader.read('explicitToJson').literalValue as bool?, @@ -101,6 +102,7 @@ ClassConfig mergeConfig( constructor: constructor, createFactory: annotation.createFactory ?? config.createFactory, createToJson: annotation.createToJson ?? config.createToJson, + createJsonMeta: annotation.createJsonMeta ?? config.createJsonMeta, disallowUnrecognizedKeys: annotation.disallowUnrecognizedKeys ?? config.disallowUnrecognizedKeys, explicitToJson: annotation.explicitToJson ?? config.explicitToJson, diff --git a/json_serializable/test/config_test.dart b/json_serializable/test/config_test.dart index 811567b81..f90f14256 100644 --- a/json_serializable/test/config_test.dart +++ b/json_serializable/test/config_test.dart @@ -152,6 +152,7 @@ const _invalidConfig = { 'checked': 42, 'constructor': 42, 'create_factory': 42, + 'create_json_meta': 42, 'create_to_json': 42, 'disallow_unrecognized_keys': 42, 'explicit_to_json': 42, diff --git a/json_serializable/test/integration/integration_test.dart b/json_serializable/test/integration/integration_test.dart index 22dc186aa..5be29f21d 100644 --- a/json_serializable/test/integration/integration_test.dart +++ b/json_serializable/test/integration/integration_test.dart @@ -7,6 +7,7 @@ import 'package:test/test.dart'; import '../test_utils.dart'; import 'json_enum_example.dart'; +import 'json_meta_example.dart'; import 'json_test_common.dart' show Category, Platform, StatusCode; import 'json_test_example.dart'; @@ -322,4 +323,14 @@ void main() { isNull, ); }); + + test(r'_$ModelJsonMeta', () { + expect( + modelMeta, + { + 'firstName': 'first-name', + 'lastName': 'LAST_NAME', + }, + ); + }); } diff --git a/json_serializable/test/integration/json_meta_example.dart b/json_serializable/test/integration/json_meta_example.dart new file mode 100644 index 000000000..3006e0ea7 --- /dev/null +++ b/json_serializable/test/integration/json_meta_example.dart @@ -0,0 +1,28 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'json_meta_example.g.dart'; + +@JsonSerializable(createJsonMeta: true, fieldRename: FieldRename.kebab) +class Model { + Model({ + required this.firstName, + required this.lastName, + this.ignoredName, + }); + + factory Model.fromJson(Map json) => _$ModelFromJson(json); + + final String firstName; + + @JsonKey(name: 'LAST_NAME') + final String lastName; + + @JsonKey(ignore: true) + final String? ignoredName; + + String get fullName => '$firstName $lastName'; + + Map toJson() => _$ModelToJson(this); +} + +const modelMeta = _$ModelJsonMeta; diff --git a/json_serializable/test/integration/json_meta_example.g.dart b/json_serializable/test/integration/json_meta_example.g.dart new file mode 100644 index 000000000..5ab3816ca --- /dev/null +++ b/json_serializable/test/integration/json_meta_example.g.dart @@ -0,0 +1,24 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ignore_for_file: lines_longer_than_80_chars, text_direction_code_point_in_literal + +part of 'json_meta_example.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Model _$ModelFromJson(Map json) => Model( + firstName: json['first-name'] as String, + lastName: json['LAST_NAME'] as String, + ); + +const _$ModelJsonMeta = { + 'firstName': 'first-name', + 'lastName': 'LAST_NAME', +}; + +Map _$ModelToJson(Model instance) => { + 'first-name': instance.firstName, + 'LAST_NAME': instance.lastName, + }; diff --git a/json_serializable/test/shared_config.dart b/json_serializable/test/shared_config.dart index 8ee8ca585..504e1cd41 100644 --- a/json_serializable/test/shared_config.dart +++ b/json_serializable/test/shared_config.dart @@ -19,6 +19,7 @@ final generatorConfigNonDefaultJson = constructor: 'something', createFactory: false, createToJson: false, + createJsonMeta: true, disallowUnrecognizedKeys: true, explicitToJson: true, fieldRename: FieldRename.kebab, diff --git a/json_serializable/test/test_sources/test_sources.dart b/json_serializable/test/test_sources/test_sources.dart index c0d93c839..faf7b9e82 100644 --- a/json_serializable/test/test_sources/test_sources.dart +++ b/json_serializable/test/test_sources/test_sources.dart @@ -15,6 +15,7 @@ class ConfigurationImplicitDefaults { constructor: '', createFactory: true, createToJson: true, + createJsonMeta: false, disallowUnrecognizedKeys: false, explicitToJson: false, fieldRename: FieldRename.none,