Skip to content

Commit 55d68f4

Browse files
authored
Use map syntax to clean up null handling in toJson functions (google#1443)
1 parent 9ccbbb2 commit 55d68f4

17 files changed

+261
-461
lines changed

_test_yaml/test/src/build_config.g.dart

Lines changed: 17 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example/lib/example.g.dart

Lines changed: 18 additions & 35 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example/test/example_test.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@ import 'package:test/test.dart';
1010

1111
void main() {
1212
test('JsonSerializable', () {
13-
final person = Person('Inigo', 'Montoya', DateTime(1560, 5, 5))
14-
..orders = [Order(DateTime.now())..item = (Item()..count = 42)];
13+
final person = Person(
14+
'Inigo',
15+
'Montoya',
16+
DateTime(1560, 5, 5),
17+
middleName: 'Bob',
18+
)..orders = [Order(DateTime.now())..item = (Item()..count = 42)];
1519

1620
final personJson = loudEncode(person);
1721

json_serializable/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
## 6.8.1-wip
1+
## 6.9.0-wip
22

3+
- Use conditional map syntax to clean up `null` handling in `toJson` functions.
34
- Require Dart 3.5
45

56
## 6.8.0

json_serializable/lib/src/constants.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
/// Name used for closure argument when generating calls to `map`.
66
const closureArg = 'e';
77

8-
const generatedLocalVarName = 'val';
9-
const toJsonMapHelperName = 'writeNotNull';
8+
const generatedLocalVarName = 'value';
109

1110
const converterOrKeyInstructions = r'''
1211
* Use `JsonConverter`

json_serializable/lib/src/encoder_helper.dart

Lines changed: 14 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -97,18 +97,22 @@ mixin EncodeHelper implements HelperCore {
9797

9898
if (config.genericArgumentFactories) _writeGenericArgumentFactories(buffer);
9999

100-
buffer.write(') ');
100+
buffer
101+
..write(') ')
102+
..writeln('=> <String, dynamic>{')
103+
..writeAll(accessibleFields.map((field) {
104+
final access = _fieldAccess(field);
101105

102-
final canWriteAllJsonValuesWithoutNullCheck =
103-
accessibleFields.every(_canWriteJsonWithoutNullCheck);
106+
final keyExpression = safeNameAccess(field);
107+
final valueExpression = _serializeField(field, access);
104108

105-
if (canWriteAllJsonValuesWithoutNullCheck) {
106-
// write simple `toJson` method that includes all keys...
107-
_writeToJsonSimple(buffer, accessibleFields);
108-
} else {
109-
// At least one field should be excluded if null
110-
_writeToJsonWithNullChecks(buffer, accessibleFields);
111-
}
109+
final keyValuePair = _canWriteJsonWithoutNullCheck(field)
110+
? '$keyExpression: $valueExpression'
111+
: 'if ($valueExpression case final $generatedLocalVarName?) '
112+
'$keyExpression: $generatedLocalVarName';
113+
return ' $keyValuePair,\n';
114+
}))
115+
..writeln('};');
112116

113117
yield buffer.toString();
114118
}
@@ -125,81 +129,8 @@ mixin EncodeHelper implements HelperCore {
125129
}
126130
}
127131

128-
void _writeToJsonSimple(StringBuffer buffer, Iterable<FieldElement> fields) {
129-
buffer
130-
..writeln('=> <String, dynamic>{')
131-
..writeAll(fields.map((field) {
132-
final access = _fieldAccess(field);
133-
final value =
134-
'${safeNameAccess(field)}: ${_serializeField(field, access)}';
135-
return ' $value,\n';
136-
}))
137-
..writeln('};');
138-
}
139-
140132
static const _toJsonParamName = 'instance';
141133

142-
void _writeToJsonWithNullChecks(
143-
StringBuffer buffer,
144-
Iterable<FieldElement> fields,
145-
) {
146-
buffer
147-
..writeln('{')
148-
..writeln(' final $generatedLocalVarName = <String, dynamic>{');
149-
150-
// Note that the map literal is left open above. As long as target fields
151-
// don't need to be intercepted by the `only if null` logic, write them
152-
// to the map literal directly. In theory, should allow more efficient
153-
// serialization.
154-
var directWrite = true;
155-
156-
for (final field in fields) {
157-
var safeFieldAccess = _fieldAccess(field);
158-
final safeJsonKeyString = safeNameAccess(field);
159-
160-
// If `fieldName` collides with one of the local helpers, prefix
161-
// access with `this.`.
162-
if (safeFieldAccess == generatedLocalVarName ||
163-
safeFieldAccess == toJsonMapHelperName) {
164-
safeFieldAccess = 'this.$safeFieldAccess';
165-
}
166-
167-
final expression = _serializeField(field, safeFieldAccess);
168-
if (_canWriteJsonWithoutNullCheck(field)) {
169-
if (directWrite) {
170-
buffer.writeln(' $safeJsonKeyString: $expression,');
171-
} else {
172-
buffer.writeln(
173-
' $generatedLocalVarName[$safeJsonKeyString] = $expression;');
174-
}
175-
} else {
176-
if (directWrite) {
177-
// close the still-open map literal
178-
buffer
179-
..writeln(' };')
180-
..writeln()
181-
182-
// write the helper to be used by all following null-excluding
183-
// fields
184-
..writeln('''
185-
void $toJsonMapHelperName(String key, dynamic value) {
186-
if (value != null) {
187-
$generatedLocalVarName[key] = value;
188-
}
189-
}
190-
''');
191-
directWrite = false;
192-
}
193-
buffer.writeln(
194-
' $toJsonMapHelperName($safeJsonKeyString, $expression);');
195-
}
196-
}
197-
198-
buffer
199-
..writeln(' return $generatedLocalVarName;')
200-
..writeln(' }');
201-
}
202-
203134
String _serializeField(FieldElement field, String accessExpression) {
204135
try {
205136
return getHelperContext(field)

json_serializable/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: json_serializable
2-
version: 6.8.1-wip
2+
version: 6.9.0-wip
33
description: >-
44
Automatically generate code for converting to and from JSON by annotating
55
Dart classes.

json_serializable/test/custom_configuration_test.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,6 @@ Map<String, dynamic> _$TrivialNestedNonNullableToJson(
214214
test('some', () async {
215215
final output = await runForElementNamed('IncludeIfNullAll');
216216
expect(output, isNot(contains(generatedLocalVarName)));
217-
expect(output, isNot(contains(toJsonMapHelperName)));
218217
});
219218
});
220219
}

json_serializable/test/integration/converter_examples.g.dart

Lines changed: 27 additions & 42 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

json_serializable/test/integration/create_per_field_to_json_example.g.dart

Lines changed: 11 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)