diff --git a/packages/_internal/lib/models.dart b/packages/_internal/lib/models.dart index bc934dd9..be0a2673 100644 --- a/packages/_internal/lib/models.dart +++ b/packages/_internal/lib/models.dart @@ -101,6 +101,7 @@ class Data with _$Data { required GenericsDefinitionTemplate genericsDefinitionTemplate, required GenericsParameterTemplate genericsParameterTemplate, required bool shouldUseExtends, + required bool genericArgumentFactories, }) = _Data; } diff --git a/packages/_internal/lib/models.freezed.dart b/packages/_internal/lib/models.freezed.dart index 9d82f9a3..85eb285a 100644 --- a/packages/_internal/lib/models.freezed.dart +++ b/packages/_internal/lib/models.freezed.dart @@ -1085,7 +1085,8 @@ class _$DataTearOff { required List constructors, required GenericsDefinitionTemplate genericsDefinitionTemplate, required GenericsParameterTemplate genericsParameterTemplate, - required bool shouldUseExtends}) { + required bool shouldUseExtends, + required bool genericArgumentFactories}) { return _Data( name: name, unionKey: unionKey, @@ -1102,6 +1103,7 @@ class _$DataTearOff { genericsDefinitionTemplate: genericsDefinitionTemplate, genericsParameterTemplate: genericsParameterTemplate, shouldUseExtends: shouldUseExtends, + genericArgumentFactories: genericArgumentFactories, ); } } @@ -1129,6 +1131,7 @@ mixin _$Data { GenericsParameterTemplate get genericsParameterTemplate => throw _privateConstructorUsedError; bool get shouldUseExtends => throw _privateConstructorUsedError; + bool get genericArgumentFactories => throw _privateConstructorUsedError; @JsonKey(ignore: true) $DataCopyWith get copyWith => throw _privateConstructorUsedError; @@ -1153,7 +1156,8 @@ abstract class $DataCopyWith<$Res> { List constructors, GenericsDefinitionTemplate genericsDefinitionTemplate, GenericsParameterTemplate genericsParameterTemplate, - bool shouldUseExtends}); + bool shouldUseExtends, + bool genericArgumentFactories}); $MapConfigCopyWith<$Res> get map; $WhenConfigCopyWith<$Res> get when; @@ -1184,6 +1188,7 @@ class _$DataCopyWithImpl<$Res> implements $DataCopyWith<$Res> { Object? genericsDefinitionTemplate = freezed, Object? genericsParameterTemplate = freezed, Object? shouldUseExtends = freezed, + Object? genericArgumentFactories = freezed, }) { return _then(_value.copyWith( name: name == freezed @@ -1246,6 +1251,10 @@ class _$DataCopyWithImpl<$Res> implements $DataCopyWith<$Res> { ? _value.shouldUseExtends : shouldUseExtends // ignore: cast_nullable_to_non_nullable as bool, + genericArgumentFactories: genericArgumentFactories == freezed + ? _value.genericArgumentFactories + : genericArgumentFactories // ignore: cast_nullable_to_non_nullable + as bool, )); } @@ -1284,7 +1293,8 @@ abstract class _$DataCopyWith<$Res> implements $DataCopyWith<$Res> { List constructors, GenericsDefinitionTemplate genericsDefinitionTemplate, GenericsParameterTemplate genericsParameterTemplate, - bool shouldUseExtends}); + bool shouldUseExtends, + bool genericArgumentFactories}); @override $MapConfigCopyWith<$Res> get map; @@ -1318,6 +1328,7 @@ class __$DataCopyWithImpl<$Res> extends _$DataCopyWithImpl<$Res> Object? genericsDefinitionTemplate = freezed, Object? genericsParameterTemplate = freezed, Object? shouldUseExtends = freezed, + Object? genericArgumentFactories = freezed, }) { return _then(_Data( name: name == freezed @@ -1380,6 +1391,10 @@ class __$DataCopyWithImpl<$Res> extends _$DataCopyWithImpl<$Res> ? _value.shouldUseExtends : shouldUseExtends // ignore: cast_nullable_to_non_nullable as bool, + genericArgumentFactories: genericArgumentFactories == freezed + ? _value.genericArgumentFactories + : genericArgumentFactories // ignore: cast_nullable_to_non_nullable + as bool, )); } } @@ -1402,7 +1417,8 @@ class _$_Data implements _Data { required this.constructors, required this.genericsDefinitionTemplate, required this.genericsParameterTemplate, - required this.shouldUseExtends}) + required this.shouldUseExtends, + required this.genericArgumentFactories}) : assert(constructors.isNotEmpty); @override @@ -1435,10 +1451,12 @@ class _$_Data implements _Data { final GenericsParameterTemplate genericsParameterTemplate; @override final bool shouldUseExtends; + @override + final bool genericArgumentFactories; @override String toString() { - return 'Data(name: $name, unionKey: $unionKey, generateCopyWith: $generateCopyWith, generateEqual: $generateEqual, generateToString: $generateToString, map: $map, when: $when, generateFromJson: $generateFromJson, generateToJson: $generateToJson, makeCollectionsImmutable: $makeCollectionsImmutable, concretePropertiesName: $concretePropertiesName, constructors: $constructors, genericsDefinitionTemplate: $genericsDefinitionTemplate, genericsParameterTemplate: $genericsParameterTemplate, shouldUseExtends: $shouldUseExtends)'; + return 'Data(name: $name, unionKey: $unionKey, generateCopyWith: $generateCopyWith, generateEqual: $generateEqual, generateToString: $generateToString, map: $map, when: $when, generateFromJson: $generateFromJson, generateToJson: $generateToJson, makeCollectionsImmutable: $makeCollectionsImmutable, concretePropertiesName: $concretePropertiesName, constructors: $constructors, genericsDefinitionTemplate: $genericsDefinitionTemplate, genericsParameterTemplate: $genericsParameterTemplate, shouldUseExtends: $shouldUseExtends, genericArgumentFactories: $genericArgumentFactories)'; } @override @@ -1476,7 +1494,10 @@ class _$_Data implements _Data { genericsParameterTemplate) || other.genericsParameterTemplate == genericsParameterTemplate) && (identical(other.shouldUseExtends, shouldUseExtends) || - other.shouldUseExtends == shouldUseExtends)); + other.shouldUseExtends == shouldUseExtends) && + (identical( + other.genericArgumentFactories, genericArgumentFactories) || + other.genericArgumentFactories == genericArgumentFactories)); } @override @@ -1496,7 +1517,8 @@ class _$_Data implements _Data { const DeepCollectionEquality().hash(constructors), genericsDefinitionTemplate, genericsParameterTemplate, - shouldUseExtends); + shouldUseExtends, + genericArgumentFactories); @JsonKey(ignore: true) @override @@ -1520,7 +1542,8 @@ abstract class _Data implements Data { required List constructors, required GenericsDefinitionTemplate genericsDefinitionTemplate, required GenericsParameterTemplate genericsParameterTemplate, - required bool shouldUseExtends}) = _$_Data; + required bool shouldUseExtends, + required bool genericArgumentFactories}) = _$_Data; @override String get name; @@ -1553,6 +1576,8 @@ abstract class _Data implements Data { @override bool get shouldUseExtends; @override + bool get genericArgumentFactories; + @override @JsonKey(ignore: true) _$DataCopyWith<_Data> get copyWith => throw _privateConstructorUsedError; } diff --git a/packages/freezed/lib/src/freezed_generator.dart b/packages/freezed/lib/src/freezed_generator.dart index 79a4a897..ef67edc8 100644 --- a/packages/freezed/lib/src/freezed_generator.dart +++ b/packages/freezed/lib/src/freezed_generator.dart @@ -101,6 +101,7 @@ class FreezedGenerator extends ParserGenerator { generateEqual: configs.equal ?? !_hasCustomEquals(element), generateFromJson: configs.fromJson ?? await needsJsonSerializable, generateToJson: configs.toJson ?? await needsJsonSerializable, + genericArgumentFactories: configs.genericArgumentFactories, map: MapConfig( map: configs.map?.map ?? shouldGenerateUnions, mapOrNull: configs.map?.mapOrNull ?? shouldGenerateUnions, @@ -494,6 +495,11 @@ Read here: https://github.com/rrousselGit/freezed/blob/master/packages/freezed/C decode: (obj) => obj.toBoolValue(), orElse: () => _buildYamlConfigs.toJson, ), + genericArgumentFactories: annotation.decodeField( + 'genericArgumentFactories', + decode: (obj) => obj.toBoolValue()!, + orElse: () => _buildYamlConfigs.genericArgumentFactories, + ), toStringOverride: annotation.decodeField( 'toStringOverride', decode: (obj) => obj.toBoolValue(), @@ -570,6 +576,7 @@ Read here: https://github.com/rrousselGit/freezed/blob/master/packages/freezed/C constructors: data.constructors, genericParameters: data.genericsParameterTemplate, genericDefinitions: data.genericsDefinitionTemplate, + genericArgumentFactories: data.genericArgumentFactories, ); } diff --git a/packages/freezed/lib/src/models.dart b/packages/freezed/lib/src/models.dart index f32facde..0f2e42e4 100644 --- a/packages/freezed/lib/src/models.dart +++ b/packages/freezed/lib/src/models.dart @@ -91,6 +91,7 @@ class Data with _$Data { required GenericsDefinitionTemplate genericsDefinitionTemplate, required GenericsParameterTemplate genericsParameterTemplate, required bool shouldUseExtends, + required bool genericArgumentFactories, }) = _Data; } diff --git a/packages/freezed/lib/src/models.freezed.dart b/packages/freezed/lib/src/models.freezed.dart index 9d82f9a3..85eb285a 100644 --- a/packages/freezed/lib/src/models.freezed.dart +++ b/packages/freezed/lib/src/models.freezed.dart @@ -1085,7 +1085,8 @@ class _$DataTearOff { required List constructors, required GenericsDefinitionTemplate genericsDefinitionTemplate, required GenericsParameterTemplate genericsParameterTemplate, - required bool shouldUseExtends}) { + required bool shouldUseExtends, + required bool genericArgumentFactories}) { return _Data( name: name, unionKey: unionKey, @@ -1102,6 +1103,7 @@ class _$DataTearOff { genericsDefinitionTemplate: genericsDefinitionTemplate, genericsParameterTemplate: genericsParameterTemplate, shouldUseExtends: shouldUseExtends, + genericArgumentFactories: genericArgumentFactories, ); } } @@ -1129,6 +1131,7 @@ mixin _$Data { GenericsParameterTemplate get genericsParameterTemplate => throw _privateConstructorUsedError; bool get shouldUseExtends => throw _privateConstructorUsedError; + bool get genericArgumentFactories => throw _privateConstructorUsedError; @JsonKey(ignore: true) $DataCopyWith get copyWith => throw _privateConstructorUsedError; @@ -1153,7 +1156,8 @@ abstract class $DataCopyWith<$Res> { List constructors, GenericsDefinitionTemplate genericsDefinitionTemplate, GenericsParameterTemplate genericsParameterTemplate, - bool shouldUseExtends}); + bool shouldUseExtends, + bool genericArgumentFactories}); $MapConfigCopyWith<$Res> get map; $WhenConfigCopyWith<$Res> get when; @@ -1184,6 +1188,7 @@ class _$DataCopyWithImpl<$Res> implements $DataCopyWith<$Res> { Object? genericsDefinitionTemplate = freezed, Object? genericsParameterTemplate = freezed, Object? shouldUseExtends = freezed, + Object? genericArgumentFactories = freezed, }) { return _then(_value.copyWith( name: name == freezed @@ -1246,6 +1251,10 @@ class _$DataCopyWithImpl<$Res> implements $DataCopyWith<$Res> { ? _value.shouldUseExtends : shouldUseExtends // ignore: cast_nullable_to_non_nullable as bool, + genericArgumentFactories: genericArgumentFactories == freezed + ? _value.genericArgumentFactories + : genericArgumentFactories // ignore: cast_nullable_to_non_nullable + as bool, )); } @@ -1284,7 +1293,8 @@ abstract class _$DataCopyWith<$Res> implements $DataCopyWith<$Res> { List constructors, GenericsDefinitionTemplate genericsDefinitionTemplate, GenericsParameterTemplate genericsParameterTemplate, - bool shouldUseExtends}); + bool shouldUseExtends, + bool genericArgumentFactories}); @override $MapConfigCopyWith<$Res> get map; @@ -1318,6 +1328,7 @@ class __$DataCopyWithImpl<$Res> extends _$DataCopyWithImpl<$Res> Object? genericsDefinitionTemplate = freezed, Object? genericsParameterTemplate = freezed, Object? shouldUseExtends = freezed, + Object? genericArgumentFactories = freezed, }) { return _then(_Data( name: name == freezed @@ -1380,6 +1391,10 @@ class __$DataCopyWithImpl<$Res> extends _$DataCopyWithImpl<$Res> ? _value.shouldUseExtends : shouldUseExtends // ignore: cast_nullable_to_non_nullable as bool, + genericArgumentFactories: genericArgumentFactories == freezed + ? _value.genericArgumentFactories + : genericArgumentFactories // ignore: cast_nullable_to_non_nullable + as bool, )); } } @@ -1402,7 +1417,8 @@ class _$_Data implements _Data { required this.constructors, required this.genericsDefinitionTemplate, required this.genericsParameterTemplate, - required this.shouldUseExtends}) + required this.shouldUseExtends, + required this.genericArgumentFactories}) : assert(constructors.isNotEmpty); @override @@ -1435,10 +1451,12 @@ class _$_Data implements _Data { final GenericsParameterTemplate genericsParameterTemplate; @override final bool shouldUseExtends; + @override + final bool genericArgumentFactories; @override String toString() { - return 'Data(name: $name, unionKey: $unionKey, generateCopyWith: $generateCopyWith, generateEqual: $generateEqual, generateToString: $generateToString, map: $map, when: $when, generateFromJson: $generateFromJson, generateToJson: $generateToJson, makeCollectionsImmutable: $makeCollectionsImmutable, concretePropertiesName: $concretePropertiesName, constructors: $constructors, genericsDefinitionTemplate: $genericsDefinitionTemplate, genericsParameterTemplate: $genericsParameterTemplate, shouldUseExtends: $shouldUseExtends)'; + return 'Data(name: $name, unionKey: $unionKey, generateCopyWith: $generateCopyWith, generateEqual: $generateEqual, generateToString: $generateToString, map: $map, when: $when, generateFromJson: $generateFromJson, generateToJson: $generateToJson, makeCollectionsImmutable: $makeCollectionsImmutable, concretePropertiesName: $concretePropertiesName, constructors: $constructors, genericsDefinitionTemplate: $genericsDefinitionTemplate, genericsParameterTemplate: $genericsParameterTemplate, shouldUseExtends: $shouldUseExtends, genericArgumentFactories: $genericArgumentFactories)'; } @override @@ -1476,7 +1494,10 @@ class _$_Data implements _Data { genericsParameterTemplate) || other.genericsParameterTemplate == genericsParameterTemplate) && (identical(other.shouldUseExtends, shouldUseExtends) || - other.shouldUseExtends == shouldUseExtends)); + other.shouldUseExtends == shouldUseExtends) && + (identical( + other.genericArgumentFactories, genericArgumentFactories) || + other.genericArgumentFactories == genericArgumentFactories)); } @override @@ -1496,7 +1517,8 @@ class _$_Data implements _Data { const DeepCollectionEquality().hash(constructors), genericsDefinitionTemplate, genericsParameterTemplate, - shouldUseExtends); + shouldUseExtends, + genericArgumentFactories); @JsonKey(ignore: true) @override @@ -1520,7 +1542,8 @@ abstract class _Data implements Data { required List constructors, required GenericsDefinitionTemplate genericsDefinitionTemplate, required GenericsParameterTemplate genericsParameterTemplate, - required bool shouldUseExtends}) = _$_Data; + required bool shouldUseExtends, + required bool genericArgumentFactories}) = _$_Data; @override String get name; @@ -1553,6 +1576,8 @@ abstract class _Data implements Data { @override bool get shouldUseExtends; @override + bool get genericArgumentFactories; + @override @JsonKey(ignore: true) _$DataCopyWith<_Data> get copyWith => throw _privateConstructorUsedError; } diff --git a/packages/freezed/lib/src/templates/abstract_template.dart b/packages/freezed/lib/src/templates/abstract_template.dart index 8ad4c007..c588923e 100644 --- a/packages/freezed/lib/src/templates/abstract_template.dart +++ b/packages/freezed/lib/src/templates/abstract_template.dart @@ -45,9 +45,12 @@ ${copyWith?.commonContreteImpl(commonProperties) ?? ''} '''; } + String get _toJsonParams => toJsonParameters( + data.genericsParameterTemplate, data.genericArgumentFactories); String get _toJson { if (!data.generateToJson) return ''; - return 'Map toJson() => throw $privConstUsedErrorVarName;'; + return 'Map toJson($_toJsonParams)' + ' => throw $privConstUsedErrorVarName;'; } String get _when { diff --git a/packages/freezed/lib/src/templates/concrete_template.dart b/packages/freezed/lib/src/templates/concrete_template.dart index 35904ad3..7ab1e297 100644 --- a/packages/freezed/lib/src/templates/concrete_template.dart +++ b/packages/freezed/lib/src/templates/concrete_template.dart @@ -45,6 +45,9 @@ class Concrete { final params = [ if (data.generateToJson == false) 'createToJson: false', if (data.generateFromJson == false) 'createFactory: false', + if (data.genericsParameterTemplate.typeParameters.isNotEmpty && + data.genericArgumentFactories == true) + 'genericArgumentFactories: true', ].join(','); jsonSerializable = '@JsonSerializable($params)'; @@ -267,23 +270,37 @@ final String \$type; return constructor.isConst ? 'const' : ''; } + String get _fromJsonArgs => fromJsonArguments( + data.genericsParameterTemplate, data.genericArgumentFactories); + + String get _fromJsonParams => fromJsonParameters( + data.genericsParameterTemplate, data.genericArgumentFactories); + String get _redirectedFromJsonConstructor { if (!data.generateFromJson) return ''; - return 'factory ${constructor.redirectedName}.fromJson(Map json) = $concreteName${data.genericsParameterTemplate}.fromJson;'; + return 'factory ${constructor.redirectedName}.fromJson(Map json$_fromJsonParams)' + ' = $concreteName${data.genericsParameterTemplate}.fromJson;'; } String get _concreteFromJsonConstructor { if (!data.generateFromJson) return ''; - return 'factory $concreteName.fromJson(Map json) => _\$${nonPrivateConcreteName}FromJson(json);'; + return 'factory $concreteName.fromJson(Map json$_fromJsonParams)' + ' => _\$${nonPrivateConcreteName}FromJson(json$_fromJsonArgs);'; } + String get _toJsonParams => toJsonParameters( + data.genericsParameterTemplate, data.genericArgumentFactories); + + String get _toJsonArgs => toJsonArguments( + data.genericsParameterTemplate, data.genericArgumentFactories); + String get _toJson { if (!data.generateToJson) return ''; return ''' @override -Map toJson() { - return _\$${nonPrivateConcreteName}ToJson(this); +Map toJson($_toJsonParams) { + return _\$${nonPrivateConcreteName}ToJson${data.genericsParameterTemplate}(this, $_toJsonArgs); }'''; } diff --git a/packages/freezed/lib/src/templates/from_json_template.dart b/packages/freezed/lib/src/templates/from_json_template.dart index 328e2e9a..20b595cf 100644 --- a/packages/freezed/lib/src/templates/from_json_template.dart +++ b/packages/freezed/lib/src/templates/from_json_template.dart @@ -2,6 +2,7 @@ import 'package:collection/collection.dart'; import 'package:freezed/src/templates/parameter_template.dart'; import '../models.dart'; +import 'prototypes.dart'; class FromJson { FromJson({ @@ -10,6 +11,7 @@ class FromJson { required this.constructors, required this.genericParameters, required this.genericDefinitions, + required this.genericArgumentFactories, }); final String name; @@ -17,6 +19,7 @@ class FromJson { final List constructors; final GenericsParameterTemplate genericParameters; final GenericsDefinitionTemplate genericDefinitions; + final bool genericArgumentFactories; @override String toString() { @@ -24,7 +27,7 @@ class FromJson { if (constructors.length == 1) { content = - 'return ${constructors.first.redirectedName}$genericParameters.fromJson(json);'; + 'return ${constructors.first.redirectedName}$genericParameters.fromJson(json${fromJsonArguments(genericParameters, genericArgumentFactories)});'; } else { final cases = constructors .where((element) => !element.isFallback) @@ -34,7 +37,7 @@ class FromJson { return ''' case '$caseName': - return $concreteName$genericParameters.fromJson(json); + return $concreteName$genericParameters.fromJson(json${fromJsonArguments(genericParameters, genericArgumentFactories)}); '''; }).join(); @@ -45,7 +48,7 @@ class FromJson { constructors.singleWhereOrNull((element) => element.isFallback); if (fallbackConstructor != null) { defaultCase = - 'return ${fallbackConstructor.redirectedName}$genericParameters.fromJson(json);'; + 'return ${fallbackConstructor.redirectedName}$genericParameters.fromJson(json${fromJsonArguments(genericParameters, genericArgumentFactories)});'; } content = ''' @@ -58,7 +61,7 @@ class FromJson { } return ''' -$name$genericParameters _\$${name}FromJson$genericDefinitions(Map json) { +$name$genericParameters _\$${name}FromJson$genericDefinitions(Map json${fromJsonParameters(genericParameters, genericArgumentFactories)}) { $content } '''; diff --git a/packages/freezed/lib/src/templates/prototypes.dart b/packages/freezed/lib/src/templates/prototypes.dart index 68fd742b..ccba9f73 100644 --- a/packages/freezed/lib/src/templates/prototypes.dart +++ b/packages/freezed/lib/src/templates/prototypes.dart @@ -229,3 +229,43 @@ bool isDefaultConstructor(ConstructorElement constructor) { String constructorNameToCallbackName(String constructorName) { return constructorName.isEmpty ? '\$default' : constructorName; } + +String toJsonParameters( + GenericsParameterTemplate parameters, + bool genericArgumentFactories, +) { + if (!genericArgumentFactories) { + return ''; + } + return '${parameters.typeParameters.map((t) => 'Object? Function($t) toJson$t').join(',')}'; +} + +String toJsonArguments( + GenericsParameterTemplate parameters, + bool genericArgumentFactories, +) { + if (!genericArgumentFactories) { + return ''; + } + return '${parameters.typeParameters.map((t) => 'toJson$t').join(',')}'; +} + +String fromJsonParameters( + GenericsParameterTemplate parameters, + bool genericArgumentFactories, +) { + if (!genericArgumentFactories) { + return ''; + } + return ',${parameters.typeParameters.map((t) => '$t Function(Object?) fromJson$t').join(',')}'; +} + +String fromJsonArguments( + GenericsParameterTemplate parameters, + bool genericArgumentFactories, +) { + if (!genericArgumentFactories) { + return ''; + } + return ',${parameters.typeParameters.map((t) => 'fromJson$t').join(',')}'; +} diff --git a/packages/freezed/test/integration/json.dart b/packages/freezed/test/integration/json.dart index e68114c6..e01aae63 100644 --- a/packages/freezed/test/integration/json.dart +++ b/packages/freezed/test/integration/json.dart @@ -104,7 +104,7 @@ class FancyCustomKey with _$FancyCustomKey { _$FancyCustomKeyFromJson(json); } -@Freezed() +@freezed class PositonalOptional with _$PositonalOptional { const factory PositonalOptional.first([int? a]) = _PositonalOptionalFirst; const factory PositonalOptional.second([int? a]) = _PositonalOptionalSecond; @@ -535,3 +535,55 @@ class EnumJson with _$EnumJson { factory EnumJson.fromJson(Map json) => _$EnumJsonFromJson(json); } + +@Freezed(genericArgumentFactories: true) +class GenericWithArgumentFactories with _$GenericWithArgumentFactories { + factory GenericWithArgumentFactories(T value, String value2) = + _GenericWithArgumentFactories; + + factory GenericWithArgumentFactories.fromJson( + Map json, T Function(Object? json) fromJsonT) => + _$GenericWithArgumentFactoriesFromJson(json, fromJsonT); +} + +@Freezed(genericArgumentFactories: true) +class GenericTupleWithArgumentFactories + with _$GenericTupleWithArgumentFactories { + factory GenericTupleWithArgumentFactories(T value1, S value2, String value3) = + _GenericTupleWithArgumentFactories; + + factory GenericTupleWithArgumentFactories.fromJson( + Map json, + T Function(Object? json) fromJsonT, + S Function(Object? json) fromJsonS) => + _$GenericTupleWithArgumentFactoriesFromJson(json, fromJsonT, fromJsonS); +} + +@Freezed(genericArgumentFactories: true) +class GenericMultiCtorWithArgumentFactories + with _$GenericMultiCtorWithArgumentFactories { + factory GenericMultiCtorWithArgumentFactories( + T first, S second, String another) = + _GenericMultiCtorWithArgumentFactories; + + factory GenericMultiCtorWithArgumentFactories.first(T first, String another) = + _GenericMultiCtorWithArgumentFactoriesVal; + + factory GenericMultiCtorWithArgumentFactories.second( + S second, String another) = + _GenericMultiCtorWithArgumentFactoriesSec; + + factory GenericMultiCtorWithArgumentFactories.both( + T first, S second, String another) = + _GenericMultiCtorWithArgumentFactoriesBoth; + + factory GenericMultiCtorWithArgumentFactories.none(String another) = + _GenericMultiCtorWithArgumentFactoriesNone; + + factory GenericMultiCtorWithArgumentFactories.fromJson( + Map json, + T Function(Object? json) fromJsonT, + S Function(Object? json) fromJsonS) => + _$GenericMultiCtorWithArgumentFactoriesFromJson( + json, fromJsonT, fromJsonS); +} diff --git a/packages/freezed/test/json_test.dart b/packages/freezed/test/json_test.dart index e50032fd..63f77e0b 100644 --- a/packages/freezed/test/json_test.dart +++ b/packages/freezed/test/json_test.dart @@ -697,6 +697,91 @@ void main() { Generic(42), ); }); + + group('JsonSerializable.genericArgumentFactories', () { + test('single ctor + single type argument', () { + expect( + GenericWithArgumentFactories.fromJson( + {'value': 'hello', 'value2': 'world'}, + (s) => s! as String, + ), + GenericWithArgumentFactories('hello', 'world'), + ); + }); + test('single ctor + two type arguments', () { + expect( + GenericTupleWithArgumentFactories.fromJson( + {'value1': 1, 'value2': 0.0, 'value3': '!'}, + (s) => s! as int, + (s) => s! as double, + ), + GenericTupleWithArgumentFactories(1, 0.0, '!'), + ); + }); + test('multi ctor + two type arguments', () { + expect( + GenericMultiCtorWithArgumentFactories.fromJson( + { + 'first': 1, + 'second': 0.0, + 'another': '!', + 'runtimeType': 'default' + }, + (s) => s! as int, + (s) => s! as double, + ), + GenericMultiCtorWithArgumentFactories(1, 0.0, '!'), + ); + expect( + GenericMultiCtorWithArgumentFactories.fromJson( + { + 'first': 1, + 'second': 0.0, + 'another': '!', + 'runtimeType': 'both' + }, + (s) => s! as int, + (s) => s! as double, + ), + GenericMultiCtorWithArgumentFactories.both(1, 0.0, '!'), + ); + expect( + GenericMultiCtorWithArgumentFactories.fromJson( + {'another': '!', 'runtimeType': 'none'}, + (s) => s! as int, + (s) => s! as double, + ), + GenericMultiCtorWithArgumentFactories.none('!'), + ); + expect( + GenericMultiCtorWithArgumentFactories.fromJson( + { + 'first': 1, + 'another': '!', + 'runtimeType': 'first' + }, + (s) => s! as int, + (s) => s! as double, + ), + GenericMultiCtorWithArgumentFactories.first(1, '!'), + ); + expect( + GenericMultiCtorWithArgumentFactories.fromJson( + { + 'second': 0.0, + 'another': '!', + 'runtimeType': 'second' + }, + (s) => s! as int, + (s) => s! as double, + ), + GenericMultiCtorWithArgumentFactories.second( + 0.0, + '!', + ), + ); + }); + }); }); test('single ctor + json can access properties/copyWith', () { diff --git a/packages/freezed_annotation/lib/freezed_annotation.dart b/packages/freezed_annotation/lib/freezed_annotation.dart index 1721680a..c835b6dd 100644 --- a/packages/freezed_annotation/lib/freezed_annotation.dart +++ b/packages/freezed_annotation/lib/freezed_annotation.dart @@ -174,6 +174,7 @@ class Freezed { this.when, this.makeCollectionsUnmodifiable, this.addImplicitFinal = true, + this.genericArgumentFactories = false, }); /// Decode the options from a build.yaml @@ -414,6 +415,23 @@ class Freezed { /// ``` final bool? toJson; + /// Whether to enable the genericArgumentFactories feature of JsonSerializable + /// + /// Defaults to false. + /// + /// This changes `fromJson(Map json) => _$ExampleFromJson(json)` + /// to have an additional parameter for each type parameter for the class + /// + /// ```dart + /// @freezed + /// class Example with _$Example { + /// factory Example(T a) = _Example; + /// + /// factory Example.fromJson(Map json, T Function(Object?) fromJsonT) => _$ExampleFromJson(json, fromJsonT)` + /// } + /// ``` + final bool genericArgumentFactories; + /// Options for customizing the generation of `map` functions /// /// If null, picks up the default values from the project's `build.yaml`. diff --git a/packages/freezed_annotation/lib/freezed_annotation.g.dart b/packages/freezed_annotation/lib/freezed_annotation.g.dart index 6012a057..73965ae8 100644 --- a/packages/freezed_annotation/lib/freezed_annotation.g.dart +++ b/packages/freezed_annotation/lib/freezed_annotation.g.dart @@ -39,6 +39,8 @@ Freezed _$FreezedFromJson(Map json) => Freezed( makeCollectionsUnmodifiable: json['make_collections_unmodifiable'] as bool? ?? true, addImplicitFinal: json['add_implicit_final'] as bool? ?? true, + genericArgumentFactories: + json['generic_argument_factories'] as bool? ?? false, ); const _$FreezedUnionCaseEnumMap = {