Skip to content

Commit a4e99e5

Browse files
committed
JsonKey.fromJson/toJson now support functions with optional arguments.
1 parent 8e6a0dd commit a4e99e5

File tree

4 files changed

+81
-8
lines changed

4 files changed

+81
-8
lines changed

json_serializable/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
`_myHelper(json['key'] as Map)` instead of
99
`_myHelper(json['key'] as Map<dynamic, dynamic>)`.
1010

11+
* `JsonKey.fromJson`/`.toJson` now support functions with optional arguments.
12+
1113
## 0.5.2
1214

13-
* If `fromJson`/`toJson` are set in `JsonKey`, apply them before any custom
15+
* If `JsonKey.fromJson`/`toJson` are set, apply them before any custom
1416
or default `TypeHelper` instances. This allows custom `DateTime` parsing,
1517
by preempting the existing `DateTime` `TypeHelper`.
1618

json_serializable/lib/src/json_key_helpers.dart

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,17 +96,16 @@ ConvertData _getFunctionName(
9696
}
9797
var functionElement = type.element as FunctionElement;
9898

99-
var positionalParams = functionElement.parameters
100-
.where((pe) => pe.isPositional)
101-
.toList();
102-
103-
if (positionalParams.length != 1) {
99+
if (functionElement.parameters.isEmpty ||
100+
functionElement.parameters.first.isNamed ||
101+
functionElement.parameters.where((pe) => !pe.isOptional).length > 1) {
104102
_throwUnsupported(
105103
element,
106104
'The `$paramName` function `${functionElement.name}` must have one '
107105
'positional paramater.');
108106
}
109107

108+
var argType = functionElement.parameters.first.type;
110109
if (isFrom) {
111110
var returnType = functionElement.returnType;
112111
if (!returnType.isAssignableTo(element.type)) {
@@ -116,7 +115,6 @@ ConvertData _getFunctionName(
116115
'`$returnType` is not compatible with field type `${element.type}`.');
117116
}
118117
} else {
119-
var argType = positionalParams.single.type;
120118
if (!element.type.isAssignableTo(argType)) {
121119
_throwUnsupported(
122120
element,
@@ -125,5 +123,5 @@ ConvertData _getFunctionName(
125123
' `${element.type}`.');
126124
}
127125
}
128-
return new ConvertData._(functionElement.name, positionalParams.single.type);
126+
return new ConvertData._(functionElement.name, argType);
129127
}

json_serializable/test/json_serializable_test.dart

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,18 @@ abstract class _$OrderSerializerMixin {
332332
'The function provided for `fromJson` must be top-level. '
333333
'Static class methods (`_staticFunc`) are not supported.');
334334
});
335+
test('BadNoArgs', () {
336+
expectThrows('BadNoArgs',
337+
'Error with `@JsonKey` on `field`. The `fromJson` function `_noArgs` must have one positional paramater.');
338+
});
339+
test('BadTwoRequiredPositional', () {
340+
expectThrows('BadTwoRequiredPositional',
341+
'Error with `@JsonKey` on `field`. The `fromJson` function `_twoArgs` must have one positional paramater.');
342+
});
343+
test('BadOneNamed', () {
344+
expectThrows('BadOneNamed',
345+
'Error with `@JsonKey` on `field`. The `fromJson` function `_oneNamed` must have one positional paramater.');
346+
});
335347
});
336348

337349
group('toJsonFunction', () {
@@ -386,6 +398,19 @@ FromDynamicCollection _$FromDynamicCollectionFromJson(
386398
: _fromDynamicIterable(json['iterableField'] as List);
387399
''');
388400
});
401+
test('OkayOneNormalOptionalPositional', () async {
402+
var output =
403+
await runForElementNamed('OkayOneNormalOptionalPositional');
404+
expect(output, contains("_oneNormalOnePositional(json['field'])"));
405+
});
406+
test('OkayOneNormalOptionalNamed', () async {
407+
var output = await runForElementNamed('OkayOneNormalOptionalNamed');
408+
expect(output, contains("_oneNormalOptionalNamed(json['field'])"));
409+
});
410+
test('OkayOnlyOptionalPositional', () async {
411+
var output = await runForElementNamed('OkayOnlyOptionalPositional');
412+
expect(output, contains("_onlyOptionalPositional(json['field'])"));
413+
});
389414
}
390415
});
391416

json_serializable/test/src/json_serializable_test_input.dart

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,3 +296,51 @@ class FromDynamicCollection {
296296
@JsonKey(fromJson: _fromDynamicIterable)
297297
String iterableField;
298298
}
299+
300+
String _noArgs() => null;
301+
302+
@JsonSerializable(createToJson: false)
303+
class BadNoArgs {
304+
@JsonKey(fromJson: _noArgs)
305+
String field;
306+
}
307+
308+
String _twoArgs(a, b) => null;
309+
310+
@JsonSerializable(createToJson: false)
311+
class BadTwoRequiredPositional {
312+
@JsonKey(fromJson: _twoArgs)
313+
String field;
314+
}
315+
316+
String _oneNamed({a}) => null;
317+
318+
@JsonSerializable(createToJson: false)
319+
class BadOneNamed {
320+
@JsonKey(fromJson: _oneNamed)
321+
String field;
322+
}
323+
324+
String _oneNormalOnePositional(a, [b]) => null;
325+
326+
@JsonSerializable(createToJson: false)
327+
class OkayOneNormalOptionalPositional {
328+
@JsonKey(fromJson: _oneNormalOnePositional)
329+
String field;
330+
}
331+
332+
String _oneNormalOptionalNamed(a, {b}) => null;
333+
334+
@JsonSerializable(createToJson: false)
335+
class OkayOneNormalOptionalNamed {
336+
@JsonKey(fromJson: _oneNormalOptionalNamed)
337+
String field;
338+
}
339+
340+
String _onlyOptionalPositional([a, b]) => null;
341+
342+
@JsonSerializable(createToJson: false)
343+
class OkayOnlyOptionalPositional {
344+
@JsonKey(fromJson: _onlyOptionalPositional)
345+
String field;
346+
}

0 commit comments

Comments
 (0)