diff --git a/json_serializable/lib/src/type_helpers/json_converter_helper.dart b/json_serializable/lib/src/type_helpers/json_converter_helper.dart index ce78f19d1..5e184ac95 100644 --- a/json_serializable/lib/src/type_helpers/json_converter_helper.dart +++ b/json_serializable/lib/src/type_helpers/json_converter_helper.dart @@ -202,6 +202,14 @@ _JsonConvertData? _typeConverterFrom( return null; } + if (targetType.isNullableType && matchingAnnotations.length == 2) { + final indexOfNonNullableConverter = matchingAnnotations + .indexWhere((element) => !element.fieldType.isNullableType); + if (indexOfNonNullableConverter >= 0) { + matchingAnnotations.removeAt(indexOfNonNullableConverter); + } + } + if (matchingAnnotations.length > 1) { final targetTypeCode = typeToCode(targetType); throw InvalidGenerationSourceError( diff --git a/json_serializable/test/json_serializable_test.dart b/json_serializable/test/json_serializable_test.dart index 5644b51cb..a4bb672f9 100644 --- a/json_serializable/test/json_serializable_test.dart +++ b/json_serializable/test/json_serializable_test.dart @@ -91,6 +91,7 @@ const _expectedAnnotatedTests = { 'JsonConvertOnField', 'JsonConverterCtorParams', 'JsonConverterDuplicateAnnotations', + 'JsonConverterIssue1339', 'JsonConverterNamedCtor', 'JsonConverterNullableToNonNullable', 'JsonConverterOnGetter', diff --git a/json_serializable/test/src/json_converter_test_input.dart b/json_serializable/test/src/json_converter_test_input.dart index ac7852f61..8e83413b4 100644 --- a/json_serializable/test/src/json_converter_test_input.dart +++ b/json_serializable/test/src/json_converter_test_input.dart @@ -126,6 +126,38 @@ class JsonConverterDuplicateAnnotations { late Duration value; } +@ShouldGenerate(r''' +JsonConverterIssue1339 _$JsonConverterIssue1339FromJson( + Map json) => + JsonConverterIssue1339() + ..value = + const _DurationMillisecondConverter().fromJson(json['value'] as int) + ..nullableValue = _$JsonConverterFromJson( + json['nullableValue'], + const _DurationMillisecondNullConverter().fromJson); + +Map _$JsonConverterIssue1339ToJson( + JsonConverterIssue1339 instance) => + { + 'value': const _DurationMillisecondConverter().toJson(instance.value), + 'nullableValue': const _DurationMillisecondNullConverter() + .toJson(instance.nullableValue), + }; + +Value? _$JsonConverterFromJson( + Object? json, + Value? Function(Json json) fromJson, +) => + json == null ? null : fromJson(json as Json); +''') +@JsonSerializable() +@_DurationMillisecondNullConverter() +@_DurationMillisecondConverter() +class JsonConverterIssue1339 { + late Duration value; + late Duration? nullableValue; +} + const _durationConverter = _DurationMillisecondConverter(); class _DurationMillisecondConverter implements JsonConverter { @@ -140,6 +172,17 @@ class _DurationMillisecondConverter implements JsonConverter { int toJson(Duration object) => throw UnimplementedError(); } +class _DurationMillisecondNullConverter + implements JsonConverter { + const _DurationMillisecondNullConverter(); + + @override + Duration? fromJson(int json) => throw UnimplementedError(); + + @override + int toJson(Duration? object) => throw UnimplementedError(); +} + @ShouldThrow( 'Generators with constructor arguments are not supported.', element: '',