From c65862dc39ec94aa1c7a2db58eee0433536f523e Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Tue, 1 Jul 2025 15:29:44 +0800 Subject: [PATCH 01/14] Enable use `@JsonKey` on constructor parameters --- json_annotation/lib/src/json_key.dart | 2 +- json_serializable/lib/src/json_key_utils.dart | 41 ++++++++++----- .../lib/src/type_helpers/config_types.dart | 5 +- json_serializable/lib/src/utils.dart | 18 +++---- .../test/json_serializable_test.dart | 2 + .../src/_json_serializable_test_input.dart | 1 + .../test/src/extends_jsonkey_override.dart | 52 +++++++++++++++++++ 7 files changed, 95 insertions(+), 26 deletions(-) create mode 100644 json_serializable/test/src/extends_jsonkey_override.dart diff --git a/json_annotation/lib/src/json_key.dart b/json_annotation/lib/src/json_key.dart index 1dc7653bc..b4da6a07e 100644 --- a/json_annotation/lib/src/json_key.dart +++ b/json_annotation/lib/src/json_key.dart @@ -8,7 +8,7 @@ import 'allowed_keys_helpers.dart'; import 'json_serializable.dart'; /// An annotation used to specify how a field is serialized. -@Target({TargetKind.field, TargetKind.getter}) +@Target({TargetKind.field, TargetKind.getter, TargetKind.parameter}) class JsonKey { /// The value to use if the source JSON does not contain this key or if the /// value is `null`. diff --git a/json_serializable/lib/src/json_key_utils.dart b/json_serializable/lib/src/json_key_utils.dart index a17e45666..9805e70a9 100644 --- a/json_serializable/lib/src/json_key_utils.dart +++ b/json_serializable/lib/src/json_key_utils.dart @@ -24,14 +24,27 @@ KeyConfig jsonKeyForField(FieldElement field, ClassConfig classAnnotation) => ); KeyConfig _from(FieldElement element, ClassConfig classAnnotation) { - // If an annotation exists on `element` the source is a 'real' field. - // If the result is `null`, check the getter – it is a property. - // TODO: setters: github.com/google/json_serializable.dart/issues/24 final obj = jsonKeyAnnotation(element); + final ctorParam = [...classAnnotation.ctorParams] + .singleWhere((e) => e!.name == element.name, orElse: () => null); + final ctorObj = ctorParam == null + ? null + : jsonKeyAnnotationForCtorParam(ctorParam); + + ConstantReader fallbackObjRead(String field) { + if (ctorObj != null && !ctorObj.isNull) { + final ctorReadResult = ctorObj.read(field); + if (!ctorReadResult.isNull) return ctorReadResult; + } + if (obj.isNull) { + return ConstantReader(null); + } + return obj.read(field); + } - final ctorParamDefault = classAnnotation.ctorParamDefaults[element.name]; + final ctorParamDefault = ctorParam?.defaultValueCode; - if (obj.isNull) { + if (obj.isNull && (ctorObj == null || ctorObj.isNull)) { return _populateJsonKey( classAnnotation, element, @@ -121,7 +134,7 @@ KeyConfig _from(FieldElement element, ClassConfig classAnnotation) { /// either the annotated field is not an `enum` or `List` or if the value in /// [fieldName] is not an `enum` value. String? createAnnotationValue(String fieldName, {bool mustBeEnum = false}) { - final annotationValue = obj.read(fieldName); + final annotationValue = fallbackObjRead(fieldName); if (annotationValue.isNull) { return null; @@ -228,16 +241,16 @@ KeyConfig _from(FieldElement element, ClassConfig classAnnotation) { } String? readValueFunctionName; - final readValue = obj.read('readValue'); + final readValue = fallbackObjRead('readValue'); if (!readValue.isNull) { readValueFunctionName = readValue.objectValue .toFunctionValue()! .qualifiedName; } - final ignore = obj.read('ignore').literalValue as bool?; - var includeFromJson = obj.read('includeFromJson').literalValue as bool?; - var includeToJson = obj.read('includeToJson').literalValue as bool?; + final ignore = fallbackObjRead('ignore').literalValue as bool?; + var includeFromJson = fallbackObjRead('includeFromJson').literalValue as bool?; + var includeToJson = fallbackObjRead('includeToJson').literalValue as bool?; if (ignore != null) { if (includeFromJson != null) { @@ -262,11 +275,11 @@ KeyConfig _from(FieldElement element, ClassConfig classAnnotation) { classAnnotation, element, defaultValue: defaultValue ?? ctorParamDefault, - disallowNullValue: obj.read('disallowNullValue').literalValue as bool?, - includeIfNull: obj.read('includeIfNull').literalValue as bool?, - name: obj.read('name').literalValue as String?, + disallowNullValue: fallbackObjRead('disallowNullValue').literalValue as bool?, + includeIfNull: fallbackObjRead('includeIfNull').literalValue as bool?, + name: fallbackObjRead('name').literalValue as String?, readValueFunctionName: readValueFunctionName, - required: obj.read('required').literalValue as bool?, + required: fallbackObjRead('required').literalValue as bool?, unknownEnumValue: createAnnotationValue( 'unknownEnumValue', mustBeEnum: true, diff --git a/json_serializable/lib/src/type_helpers/config_types.dart b/json_serializable/lib/src/type_helpers/config_types.dart index 80d258589..dee49e26a 100644 --- a/json_serializable/lib/src/type_helpers/config_types.dart +++ b/json_serializable/lib/src/type_helpers/config_types.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'package:analyzer/dart/constant/value.dart'; +import 'package:analyzer/dart/element/element.dart'; import 'package:json_annotation/json_annotation.dart'; /// Represents values from [JsonKey] when merged with local configuration. @@ -57,7 +58,7 @@ class ClassConfig { final bool genericArgumentFactories; final bool ignoreUnannotated; final bool includeIfNull; - final Map ctorParamDefaults; + final List ctorParams; final List converters; const ClassConfig({ @@ -76,7 +77,7 @@ class ClassConfig { required this.ignoreUnannotated, required this.includeIfNull, this.converters = const [], - this.ctorParamDefaults = const {}, + this.ctorParams = const [], }); factory ClassConfig.fromJsonSerializable(JsonSerializable config) => diff --git a/json_serializable/lib/src/utils.dart b/json_serializable/lib/src/utils.dart index 9f1d34bc7..03a872a5a 100644 --- a/json_serializable/lib/src/utils.dart +++ b/json_serializable/lib/src/utils.dart @@ -14,6 +14,9 @@ import 'type_helpers/config_types.dart'; const _jsonKeyChecker = TypeChecker.fromRuntime(JsonKey); +// If an annotation exists on `element` the source is a 'real' field. +// If the result is `null`, check the getter – it is a property. +// TODO: setters: github.com/google/json_serializable.dart/issues/24 DartObject? _jsonKeyAnnotation(FieldElement element) => _jsonKeyChecker.firstAnnotationOf(element) ?? (element.getter == null @@ -27,6 +30,9 @@ ConstantReader jsonKeyAnnotation(FieldElement element) => bool hasJsonKeyAnnotation(FieldElement element) => _jsonKeyAnnotation(element) != null; +ConstantReader jsonKeyAnnotationForCtorParam(ParameterElement element) => + ConstantReader(_jsonKeyChecker.firstAnnotationOf(element)); + Never throwUnsupported(FieldElement element, String message) => throw InvalidGenerationSourceError( 'Error with `@JsonKey` on the `${element.name}` field. $message', @@ -82,7 +88,7 @@ ClassConfig mergeConfig( required ClassElement classElement, }) { final annotation = _valueForAnnotation(reader); - assert(config.ctorParamDefaults.isEmpty); + assert(config.ctorParams.isEmpty); final constructor = annotation.constructor ?? config.constructor; final constructorInstance = _constructorByNameOrNull( @@ -90,13 +96,7 @@ ClassConfig mergeConfig( constructor, ); - final paramDefaultValueMap = constructorInstance == null - ? {} - : Map.fromEntries( - constructorInstance.parameters - .where((element) => element.hasDefaultValue) - .map((e) => MapEntry(e.name, e.defaultValueCode!)), - ); + final ctorParams = [...?constructorInstance?.parameters]; final converters = reader.read('converters'); @@ -120,7 +120,7 @@ ClassConfig mergeConfig( config.genericArgumentFactories), ignoreUnannotated: annotation.ignoreUnannotated ?? config.ignoreUnannotated, includeIfNull: annotation.includeIfNull ?? config.includeIfNull, - ctorParamDefaults: paramDefaultValueMap, + ctorParams: ctorParams, converters: converters.isNull ? const [] : converters.listValue, ); } diff --git a/json_serializable/test/json_serializable_test.dart b/json_serializable/test/json_serializable_test.dart index b6ff36789..0f58f71ba 100644 --- a/json_serializable/test/json_serializable_test.dart +++ b/json_serializable/test/json_serializable_test.dart @@ -49,6 +49,8 @@ const _expectedAnnotatedTests = { 'BadToFuncReturnType', 'BadTwoRequiredPositional', 'CtorDefaultValueAndJsonKeyDefaultValue', + 'CtorParamJsonKey', + 'CtorParamJsonKeyWithExtends', 'DefaultDoubleConstants', 'DefaultWithConstObject', 'DefaultWithDisallowNullRequiredClass', diff --git a/json_serializable/test/src/_json_serializable_test_input.dart b/json_serializable/test/src/_json_serializable_test_input.dart index 4db90e56f..a7b63d795 100644 --- a/json_serializable/test/src/_json_serializable_test_input.dart +++ b/json_serializable/test/src/_json_serializable_test_input.dart @@ -14,6 +14,7 @@ part 'constants_copy.dart'; part 'core_subclass_type_input.dart'; part 'default_value_input.dart'; part 'field_namer_input.dart'; +part 'extends_jsonkey_override.dart'; part 'generic_test_input.dart'; part 'inheritance_test_input.dart'; part 'json_converter_test_input.dart'; diff --git a/json_serializable/test/src/extends_jsonkey_override.dart b/json_serializable/test/src/extends_jsonkey_override.dart new file mode 100644 index 000000000..989f0e24f --- /dev/null +++ b/json_serializable/test/src/extends_jsonkey_override.dart @@ -0,0 +1,52 @@ +// @dart=3.8 + +part of '_json_serializable_test_input.dart'; + +// https://github.com/google/json_serializable.dart/issues/1437 +@ShouldGenerate(r''' +CtorParamJsonKey _$CtorParamJsonKeyFromJson(Map json) => + CtorParamJsonKey( + attributeOne: json['first'] as String, + attributeTwo: json['second'] as String, + ); + +Map _$CtorParamJsonKeyToJson(CtorParamJsonKey instance) => + { + 'first': instance.attributeOne, + 'second': instance.attributeTwo, + }; +''') +@JsonSerializable() +class CtorParamJsonKey { + CtorParamJsonKey({ + @JsonKey(name: 'first') required this.attributeOne, + @JsonKey(name: 'second') required this.attributeTwo, + }); + + @JsonKey(name: 'fake_first') + final String attributeOne; + final String attributeTwo; +} + +@ShouldGenerate(r''' +CtorParamJsonKeyWithExtends _$CtorParamJsonKeyWithExtendsFromJson( + Map json, +) => CtorParamJsonKeyWithExtends( + attributeOne: json['fake_first'] as String, + attributeTwo: json['two'] as String, +); + +Map _$CtorParamJsonKeyWithExtendsToJson( + CtorParamJsonKeyWithExtends instance, +) => { + 'fake_first': instance.attributeOne, + 'two': instance.attributeTwo, +}; +''') +@JsonSerializable() +class CtorParamJsonKeyWithExtends extends CtorParamJsonKey { + CtorParamJsonKeyWithExtends({ + required super.attributeOne, + @JsonKey(name: 'two') required super.attributeTwo, + }); +} From d38044e09532bac7f44796dc92a32decd18570a0 Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Tue, 1 Jul 2025 15:31:59 +0800 Subject: [PATCH 02/14] code format --- json_serializable/lib/src/json_key_utils.dart | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/json_serializable/lib/src/json_key_utils.dart b/json_serializable/lib/src/json_key_utils.dart index 9805e70a9..242dac119 100644 --- a/json_serializable/lib/src/json_key_utils.dart +++ b/json_serializable/lib/src/json_key_utils.dart @@ -25,8 +25,9 @@ KeyConfig jsonKeyForField(FieldElement field, ClassConfig classAnnotation) => KeyConfig _from(FieldElement element, ClassConfig classAnnotation) { final obj = jsonKeyAnnotation(element); - final ctorParam = [...classAnnotation.ctorParams] - .singleWhere((e) => e!.name == element.name, orElse: () => null); + final ctorParam = [ + ...classAnnotation.ctorParams, + ].singleWhere((e) => e!.name == element.name, orElse: () => null); final ctorObj = ctorParam == null ? null : jsonKeyAnnotationForCtorParam(ctorParam); @@ -249,7 +250,8 @@ KeyConfig _from(FieldElement element, ClassConfig classAnnotation) { } final ignore = fallbackObjRead('ignore').literalValue as bool?; - var includeFromJson = fallbackObjRead('includeFromJson').literalValue as bool?; + var includeFromJson = + fallbackObjRead('includeFromJson').literalValue as bool?; var includeToJson = fallbackObjRead('includeToJson').literalValue as bool?; if (ignore != null) { @@ -275,7 +277,8 @@ KeyConfig _from(FieldElement element, ClassConfig classAnnotation) { classAnnotation, element, defaultValue: defaultValue ?? ctorParamDefault, - disallowNullValue: fallbackObjRead('disallowNullValue').literalValue as bool?, + disallowNullValue: + fallbackObjRead('disallowNullValue').literalValue as bool?, includeIfNull: fallbackObjRead('includeIfNull').literalValue as bool?, name: fallbackObjRead('name').literalValue as String?, readValueFunctionName: readValueFunctionName, From 8a1a75815bae9985ad0ae9569fbb7e70b98818cd Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Fri, 11 Jul 2025 18:04:32 +0800 Subject: [PATCH 03/14] fix: migrate to element2 api --- json_serializable/lib/src/json_key_utils.dart | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/json_serializable/lib/src/json_key_utils.dart b/json_serializable/lib/src/json_key_utils.dart index 0d11aab4d..f99daa934 100644 --- a/json_serializable/lib/src/json_key_utils.dart +++ b/json_serializable/lib/src/json_key_utils.dart @@ -3,7 +3,6 @@ // BSD-style license that can be found in the LICENSE file. import 'package:analyzer/dart/constant/value.dart'; -import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/element2.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:build/build.dart'; @@ -151,14 +150,14 @@ KeyConfig _from(FieldElement2 element, ClassConfig classAnnotation) { // the generated code will be invalid, so skipping until we're bored // later - final functionValue = objectValue.toFunctionValue()!; + final functionValue = objectValue.toFunctionValue2()!; final invokeConst = - functionValue is ConstructorElement && functionValue.isConst + functionValue is ConstructorElement2 && functionValue.isConst ? 'const ' : ''; - return '$invokeConst${functionValue.name}()'; + return '$invokeConst${functionValue.qualifiedName}()'; } final enumFields = iterateEnumFields(annotationType); From 5e230c74ccc9481222149bff9a8afe8dfa42c272 Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Fri, 11 Jul 2025 18:24:47 +0800 Subject: [PATCH 04/14] fix: migrate to element2 api --- json_serializable/lib/src/json_key_utils.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/json_serializable/lib/src/json_key_utils.dart b/json_serializable/lib/src/json_key_utils.dart index f99daa934..7f89150ac 100644 --- a/json_serializable/lib/src/json_key_utils.dart +++ b/json_serializable/lib/src/json_key_utils.dart @@ -80,7 +80,7 @@ KeyConfig _from(FieldElement2 element, ClassConfig classAnnotation) { // literal, which is NOT supported! badType = 'Function'; } else if (!reader.isLiteral) { - badType = dartObject.type!.element?.name; + badType = dartObject.type!.element3?.name3; } if (badType != null) { @@ -208,7 +208,7 @@ KeyConfig _from(FieldElement2 element, ClassConfig classAnnotation) { (n) => n, ); - return '${annotationType.element!.name}.$enumValueName'; + return '${annotationType.element3!.name3}.$enumValueName'; } else { final defaultValueLiteral = literalForObject(fieldName, objectValue, []); if (defaultValueLiteral == null) { @@ -244,7 +244,9 @@ KeyConfig _from(FieldElement2 element, ClassConfig classAnnotation) { String? readValueFunctionName; final readValue = fallbackObjRead('readValue'); if (!readValue.isNull) { - readValueFunctionName = readValue.objectValue.toFunctionValue()!.name; + readValueFunctionName = readValue.objectValue + .toFunctionValue2()! + .qualifiedName; } final ignore = fallbackObjRead('ignore').literalValue as bool?; @@ -345,7 +347,7 @@ bool _includeIfNull( bool _interfaceTypesEqual(DartType a, DartType b) { if (a is InterfaceType && b is InterfaceType) { // Handle nullability case. Pretty sure this is fine for enums. - return a.element == b.element; + return a.element3 == b.element3; } return a == b; } From 78188329096e488a59e95615184fafca8fd336e1 Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Fri, 11 Jul 2025 18:35:33 +0800 Subject: [PATCH 05/14] fix: migrate to element2 api --- json_serializable/lib/src/json_key_utils.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/json_serializable/lib/src/json_key_utils.dart b/json_serializable/lib/src/json_key_utils.dart index 7f89150ac..930145e24 100644 --- a/json_serializable/lib/src/json_key_utils.dart +++ b/json_serializable/lib/src/json_key_utils.dart @@ -80,7 +80,7 @@ KeyConfig _from(FieldElement2 element, ClassConfig classAnnotation) { // literal, which is NOT supported! badType = 'Function'; } else if (!reader.isLiteral) { - badType = dartObject.type!.element3?.name3; + badType = dartObject.type!.element3?.name3!; } if (badType != null) { @@ -208,7 +208,7 @@ KeyConfig _from(FieldElement2 element, ClassConfig classAnnotation) { (n) => n, ); - return '${annotationType.element3!.name3}.$enumValueName'; + return '${annotationType.element3!.name3!}.$enumValueName'; } else { final defaultValueLiteral = literalForObject(fieldName, objectValue, []); if (defaultValueLiteral == null) { @@ -228,12 +228,12 @@ KeyConfig _from(FieldElement2 element, ClassConfig classAnnotation) { if (defaultValue != null && ctorParamDefault != null) { if (defaultValue == ctorParamDefault) { log.info( - 'The default value `$defaultValue` for `${element.name3}` is defined ' + 'The default value `$defaultValue` for `${element.name3!}` is defined ' 'twice in the constructor and in the `JsonKey.defaultValue`.', ); } else { log.warning( - 'The constructor parameter for `${element.name3}` has a default value ' + 'The constructor parameter for `${element.name3!}` has a default value ' '`$ctorParamDefault`, but the `JsonKey.defaultValue` value ' '`$defaultValue` will be used for missing or `null` values in JSON ' 'decoding.', From 5410e8cd0b3725cab5e1787ca800c1aab6c27926 Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Fri, 18 Jul 2025 10:34:47 +0800 Subject: [PATCH 06/14] use `where().singleOrNull` instead of `[].singleWhere(orElse: null)` --- json_serializable/lib/src/json_key_utils.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/json_serializable/lib/src/json_key_utils.dart b/json_serializable/lib/src/json_key_utils.dart index bb997d9ec..ac7fdc7fe 100644 --- a/json_serializable/lib/src/json_key_utils.dart +++ b/json_serializable/lib/src/json_key_utils.dart @@ -25,9 +25,9 @@ KeyConfig jsonKeyForField(FieldElement2 field, ClassConfig classAnnotation) => KeyConfig _from(FieldElement2 element, ClassConfig classAnnotation) { final obj = jsonKeyAnnotation(element); - final ctorParam = [ - ...classAnnotation.ctorParams, - ].singleWhere((e) => e!.name3 == element.name3, orElse: () => null); + final ctorParam = classAnnotation.ctorParams + .where((e) => e.name3 == element.name3) + .singleOrNull; final ctorObj = ctorParam == null ? null : jsonKeyAnnotationForCtorParam(ctorParam); From 44bbfde74452b53d09b5a9f8ee64857775eb6756 Mon Sep 17 00:00:00 2001 From: hhh <65709676+huanghui1998hhh@users.noreply.github.com> Date: Thu, 24 Jul 2025 14:00:12 +0800 Subject: [PATCH 07/14] Update json_serializable/lib/src/utils.dart Co-authored-by: Kevin Moore --- json_serializable/lib/src/utils.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/json_serializable/lib/src/utils.dart b/json_serializable/lib/src/utils.dart index 47f4b1c90..132207ef7 100644 --- a/json_serializable/lib/src/utils.dart +++ b/json_serializable/lib/src/utils.dart @@ -14,8 +14,8 @@ import 'type_helpers/config_types.dart'; const _jsonKeyChecker = TypeChecker.fromRuntime(JsonKey); -// If an annotation exists on `element` the source is a 'real' field. -// If the result is `null`, check the getter – it is a property. +/// If an annotation exists on `element` the source is a 'real' field. +/// If the result is `null`, check the getter – it is a property. // TODO: setters: github.com/google/json_serializable.dart/issues/24 DartObject? _jsonKeyAnnotation(FieldElement2 element) => _jsonKeyChecker.firstAnnotationOf(element) ?? From b093e69b60f87b946d81e23c296bab3a9ad5f565 Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Thu, 24 Jul 2025 14:57:49 +0800 Subject: [PATCH 08/14] add warning when `JsonKey` field conflict --- json_serializable/lib/src/json_key_utils.dart | 12 +++++++++++- .../test/src/extends_jsonkey_override.dart | 6 +++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/json_serializable/lib/src/json_key_utils.dart b/json_serializable/lib/src/json_key_utils.dart index ac7fdc7fe..f2bdf1a16 100644 --- a/json_serializable/lib/src/json_key_utils.dart +++ b/json_serializable/lib/src/json_key_utils.dart @@ -35,7 +35,17 @@ KeyConfig _from(FieldElement2 element, ClassConfig classAnnotation) { ConstantReader fallbackObjRead(String field) { if (ctorObj != null && !ctorObj.isNull) { final ctorReadResult = ctorObj.read(field); - if (!ctorReadResult.isNull) return ctorReadResult; + if (!ctorReadResult.isNull) { + if (!obj.isNull && !obj.read(field).isNull) { + log.warning( + 'Field `${element.name3}` has conflicting `JsonKey.$field` ' + 'annotations: both constructor parameter and class field have ' + 'this annotation. Using constructor parameter value.', + ); + } + + return ctorReadResult; + } } if (obj.isNull) { return ConstantReader(null); diff --git a/json_serializable/test/src/extends_jsonkey_override.dart b/json_serializable/test/src/extends_jsonkey_override.dart index 989f0e24f..ab3521499 100644 --- a/json_serializable/test/src/extends_jsonkey_override.dart +++ b/json_serializable/test/src/extends_jsonkey_override.dart @@ -15,7 +15,11 @@ Map _$CtorParamJsonKeyToJson(CtorParamJsonKey instance) => 'first': instance.attributeOne, 'second': instance.attributeTwo, }; -''') +''', expectedLogItems: [ + 'Field `attributeOne` has conflicting `JsonKey.name` annotations: both ' + 'constructor parameter and class field have this annotation. Using ' + 'constructor parameter value.', +]) @JsonSerializable() class CtorParamJsonKey { CtorParamJsonKey({ From 13339352e9e01be8ae2998061ccf8a29ce18e9d6 Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Thu, 24 Jul 2025 14:59:30 +0800 Subject: [PATCH 09/14] code format --- json_serializable/lib/src/json_key_utils.dart | 12 ++++++------ .../test/src/extends_jsonkey_override.dart | 15 +++++++++------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/json_serializable/lib/src/json_key_utils.dart b/json_serializable/lib/src/json_key_utils.dart index f2bdf1a16..99ea02842 100644 --- a/json_serializable/lib/src/json_key_utils.dart +++ b/json_serializable/lib/src/json_key_utils.dart @@ -35,13 +35,13 @@ KeyConfig _from(FieldElement2 element, ClassConfig classAnnotation) { ConstantReader fallbackObjRead(String field) { if (ctorObj != null && !ctorObj.isNull) { final ctorReadResult = ctorObj.read(field); - if (!ctorReadResult.isNull) { + if (!ctorReadResult.isNull) { if (!obj.isNull && !obj.read(field).isNull) { - log.warning( - 'Field `${element.name3}` has conflicting `JsonKey.$field` ' - 'annotations: both constructor parameter and class field have ' - 'this annotation. Using constructor parameter value.', - ); + log.warning( + 'Field `${element.name3}` has conflicting `JsonKey.$field` ' + 'annotations: both constructor parameter and class field have ' + 'this annotation. Using constructor parameter value.', + ); } return ctorReadResult; diff --git a/json_serializable/test/src/extends_jsonkey_override.dart b/json_serializable/test/src/extends_jsonkey_override.dart index ab3521499..04c1c5b34 100644 --- a/json_serializable/test/src/extends_jsonkey_override.dart +++ b/json_serializable/test/src/extends_jsonkey_override.dart @@ -3,7 +3,8 @@ part of '_json_serializable_test_input.dart'; // https://github.com/google/json_serializable.dart/issues/1437 -@ShouldGenerate(r''' +@ShouldGenerate( + r''' CtorParamJsonKey _$CtorParamJsonKeyFromJson(Map json) => CtorParamJsonKey( attributeOne: json['first'] as String, @@ -15,11 +16,13 @@ Map _$CtorParamJsonKeyToJson(CtorParamJsonKey instance) => 'first': instance.attributeOne, 'second': instance.attributeTwo, }; -''', expectedLogItems: [ - 'Field `attributeOne` has conflicting `JsonKey.name` annotations: both ' - 'constructor parameter and class field have this annotation. Using ' - 'constructor parameter value.', -]) +''', + expectedLogItems: [ + 'Field `attributeOne` has conflicting `JsonKey.name` annotations: both ' + 'constructor parameter and class field have this annotation. Using ' + 'constructor parameter value.', + ], +) @JsonSerializable() class CtorParamJsonKey { CtorParamJsonKey({ From 5c12843d5dd70f223eb30a5e99e936c14c8fb122 Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Thu, 24 Jul 2025 15:10:48 +0800 Subject: [PATCH 10/14] expand the doc for `JsonKey` --- json_annotation/lib/src/json_key.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/json_annotation/lib/src/json_key.dart b/json_annotation/lib/src/json_key.dart index b4da6a07e..599af1af1 100644 --- a/json_annotation/lib/src/json_key.dart +++ b/json_annotation/lib/src/json_key.dart @@ -8,6 +8,9 @@ import 'allowed_keys_helpers.dart'; import 'json_serializable.dart'; /// An annotation used to specify how a field is serialized. +/// +/// This annotation can be used on both class properties and constructor +/// parameters. @Target({TargetKind.field, TargetKind.getter, TargetKind.parameter}) class JsonKey { /// The value to use if the source JSON does not contain this key or if the From 3d87b8be9fcb9ed5e56c27a1b30240e62423e513 Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Thu, 24 Jul 2025 15:22:05 +0800 Subject: [PATCH 11/14] update `CHANGELOG.md` --- json_annotation/CHANGELOG.md | 1 + json_serializable/CHANGELOG.md | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/json_annotation/CHANGELOG.md b/json_annotation/CHANGELOG.md index ae0b4d43d..c43793a76 100644 --- a/json_annotation/CHANGELOG.md +++ b/json_annotation/CHANGELOG.md @@ -1,6 +1,7 @@ ## 4.9.1-wip - Require Dart 3.8 +- Support `JsonKey` annotation on constructor parameters. ## 4.9.0 diff --git a/json_serializable/CHANGELOG.md b/json_serializable/CHANGELOG.md index f8c38271e..bc1b5d6f9 100644 --- a/json_serializable/CHANGELOG.md +++ b/json_serializable/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.10.1 + +- Support `JsonKey` annotation on constructor parameters. + ## 6.10.0 - Required `analyzer: ^7.4.0`. From 9cfb5b3da45cf9477de4a567d872cda464e4a805 Mon Sep 17 00:00:00 2001 From: hhh <65709676+huanghui1998hhh@users.noreply.github.com> Date: Fri, 25 Jul 2025 10:14:15 +0800 Subject: [PATCH 12/14] Update json_serializable/CHANGELOG.md Co-authored-by: Kevin Moore --- json_serializable/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_serializable/CHANGELOG.md b/json_serializable/CHANGELOG.md index bc1b5d6f9..531396ea1 100644 --- a/json_serializable/CHANGELOG.md +++ b/json_serializable/CHANGELOG.md @@ -1,4 +1,4 @@ -## 6.10.1 +## 6.11.0 - Support `JsonKey` annotation on constructor parameters. From 2e0d4d636143ce7a0be153b85bac4bc9888d3961 Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Fri, 25 Jul 2025 10:18:07 +0800 Subject: [PATCH 13/14] code format --- json_annotation/lib/src/json_key.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_annotation/lib/src/json_key.dart b/json_annotation/lib/src/json_key.dart index 599af1af1..752219944 100644 --- a/json_annotation/lib/src/json_key.dart +++ b/json_annotation/lib/src/json_key.dart @@ -8,7 +8,7 @@ import 'allowed_keys_helpers.dart'; import 'json_serializable.dart'; /// An annotation used to specify how a field is serialized. -/// +/// /// This annotation can be used on both class properties and constructor /// parameters. @Target({TargetKind.field, TargetKind.getter, TargetKind.parameter}) From 7246cfd1db3302beec6b99bc5b09b1248d6e2b55 Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Sat, 26 Jul 2025 12:58:39 +0800 Subject: [PATCH 14/14] Update json_serializable/pubspec.yaml --- json_serializable/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_serializable/pubspec.yaml b/json_serializable/pubspec.yaml index d2184e4b9..a9d4c9fb1 100644 --- a/json_serializable/pubspec.yaml +++ b/json_serializable/pubspec.yaml @@ -1,5 +1,5 @@ name: json_serializable -version: 6.10.0 +version: 6.11.0 description: >- Automatically generate code for converting to and from JSON by annotating Dart classes.