Skip to content

Commit 75c9b24

Browse files
committed
Allow extra non-serializable fields to be passed into fromJson and ignored in toJson
1 parent 4047521 commit 75c9b24

File tree

4 files changed

+42
-13
lines changed

4 files changed

+42
-13
lines changed

json_annotation/lib/src/json_key.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ class JsonKey {
9090
/// Valid only on enum fields with a compatible enum value.
9191
final Object? unknownEnumValue;
9292

93+
final bool? extra;
94+
9395
/// Creates a new [JsonKey] instance.
9496
///
9597
/// Only required when the default behavior is not desired.
@@ -104,5 +106,6 @@ class JsonKey {
104106
this.required,
105107
this.toJson,
106108
this.unknownEnumValue,
109+
this.extra,
107110
});
108111
}

json_serializable/lib/src/decode_helper.dart

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ abstract class DecodeHelper implements HelperCore {
2424
CreateFactoryResult createFactory(
2525
Map<String, FieldElement> accessibleFields,
2626
Map<String, String> unavailableReasons,
27+
List<FieldElement> extras,
2728
) {
2829
assert(config.createFactory);
2930
final buffer = StringBuffer();
@@ -46,16 +47,27 @@ abstract class DecodeHelper implements HelperCore {
4647
}
4748
}
4849

50+
if (extras.isNotEmpty) {
51+
buffer.writeln(', {');
52+
for (final extra in extras) {
53+
if (!extra.type.isNullableType) buffer.write('required ');
54+
buffer.writeln(
55+
'${extra.type.getDisplayString(withNullability: true)} ${extra.name},');
56+
}
57+
buffer.write('}');
58+
}
59+
4960
buffer.write(') {\n');
5061

5162
String deserializeFun(String paramOrFieldName,
5263
{ParameterElement ctorParam}) =>
5364
_deserializeForField(accessibleFields[paramOrFieldName],
5465
ctorParam: ctorParam);
5566

67+
final extraNames = [for (final extra in extras) extra.name];
5668
final data = _writeConstructorInvocation(
5769
element,
58-
accessibleFields.keys,
70+
[...accessibleFields.keys, ...extraNames],
5971
accessibleFields.values
6072
.where((fe) =>
6173
!fe.isFinal ||
@@ -66,6 +78,7 @@ abstract class DecodeHelper implements HelperCore {
6678
.map((fe) => fe.name)
6779
.toList(),
6880
unavailableReasons,
81+
extraNames,
6982
deserializeFun,
7083
);
7184

@@ -237,6 +250,7 @@ _ConstructorData _writeConstructorInvocation(
237250
Iterable<String> availableConstructorParameters,
238251
Iterable<String> writableFields,
239252
Map<String, String> unavailableReasons,
253+
List<String> extras,
240254
String Function(String paramOrFieldName, {ParameterElement ctorParam})
241255
deserializeForField,
242256
) {
@@ -278,7 +292,7 @@ _ConstructorData _writeConstructorInvocation(
278292
} else {
279293
constructorArguments.add(arg);
280294
}
281-
usedCtorParamsAndFields.add(arg.name);
295+
if (!extras.contains(arg.name)) usedCtorParamsAndFields.add(arg.name);
282296
}
283297

284298
// fields that aren't already set by the constructor and that aren't final
@@ -291,17 +305,19 @@ _ConstructorData _writeConstructorInvocation(
291305
buffer
292306
..writeln()
293307
..writeAll(constructorArguments.map((paramElement) {
294-
final content =
295-
deserializeForField(paramElement.name, ctorParam: paramElement);
308+
final content = extras.contains(paramElement.name)
309+
? paramElement.name
310+
: deserializeForField(paramElement.name, ctorParam: paramElement);
296311
return ' $content,\n';
297312
}));
298313
}
299314
if (namedConstructorArguments.isNotEmpty) {
300315
buffer
301316
..writeln()
302317
..writeAll(namedConstructorArguments.map((paramElement) {
303-
final value =
304-
deserializeForField(paramElement.name, ctorParam: paramElement);
318+
final value = extras.contains(paramElement.name)
319+
? paramElement.name
320+
: deserializeForField(paramElement.name, ctorParam: paramElement);
305321
return ' ${paramElement.name}: $value,\n';
306322
}));
307323
}

json_serializable/lib/src/generator_helper.dart

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ class GeneratorHelper extends HelperCore with EncodeHelper, DecodeHelper {
5858
// these fields.
5959
final unavailableReasons = <String, String>{};
6060

61+
final extras = <FieldElement>[];
62+
6163
final accessibleFields = sortedFields.fold<Map<String, FieldElement>>(
6264
<String, FieldElement>{},
6365
(map, field) {
@@ -68,21 +70,26 @@ class GeneratorHelper extends HelperCore with EncodeHelper, DecodeHelper {
6870
unavailableReasons[field.name] =
6971
'Setter-only properties are not supported.';
7072
log.warning('Setters are ignored: ${element.name}.${field.name}');
71-
} else if (jsonKeyFor(field).ignore) {
72-
unavailableReasons[field.name] =
73-
'It is assigned to an ignored field.';
7473
} else {
75-
assert(!map.containsKey(field.name));
76-
map[field.name] = field;
74+
final jsonKey = jsonKeyFor(field);
75+
if (jsonKey.ignore) {
76+
unavailableReasons[field.name] =
77+
'It is assigned to an ignored field.';
78+
} else if (jsonKey.extra) {
79+
extras.add(field);
80+
} else {
81+
assert(!map.containsKey(field.name));
82+
map[field.name] = field;
83+
}
7784
}
78-
7985
return map;
8086
},
8187
);
8288

8389
var accessibleFieldSet = accessibleFields.values.toSet();
8490
if (config.createFactory) {
85-
final createResult = createFactory(accessibleFields, unavailableReasons);
91+
final createResult =
92+
createFactory(accessibleFields, unavailableReasons, extras);
8693
yield createResult.output;
8794

8895
accessibleFieldSet = accessibleFields.entries

json_serializable/lib/src/json_key_utils.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ JsonKey _from(FieldElement element, JsonSerializable classAnnotation) {
181181
name: obj.read('name').literalValue as String,
182182
required: obj.read('required').literalValue as bool,
183183
unknownEnumValue: _annotationValue('unknownEnumValue', mustBeEnum: true),
184+
extra: obj.read('extra').literalValue as bool,
184185
);
185186
}
186187

@@ -194,6 +195,7 @@ JsonKey _populateJsonKey(
194195
String name,
195196
bool required,
196197
Object unknownEnumValue,
198+
bool extra,
197199
}) {
198200
if (disallowNullValue == true) {
199201
if (includeIfNull == true) {
@@ -213,6 +215,7 @@ JsonKey _populateJsonKey(
213215
name: _encodedFieldName(classAnnotation, name, element),
214216
required: required ?? false,
215217
unknownEnumValue: unknownEnumValue,
218+
extra: extra ?? false,
216219
);
217220

218221
return jsonKey;

0 commit comments

Comments
 (0)