-
Notifications
You must be signed in to change notification settings - Fork 421
Add disallowUnrecognizedKeys
option
#212
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 10 commits
06bf1f6
5d5acfb
15a13fd
2756a2a
f321e74
bdd52e4
6e721ff
e800077
389fda7
8cbf830
e521eae
3eee0e0
4aabaef
7c8c1be
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,15 @@ | ||
## 0.2.7 | ||
|
||
* Added `JsonSerializable.disallowUnregognizedKeys`. | ||
* Defaults to `false` which maintains the previous behavior. | ||
* Throws an `UnrecognizedKeysException` if it finds unrecognized keys in the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this and next bullet: Put runtime notes in json_serialiable changelog There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
JSON map used to create the annotated object. | ||
* Will be captured captured and wrapped in a `CheckedFromJsonException` if | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wording? |
||
`checked` is enabled in `json_serializable`. | ||
* Added a helper function to support this option. This function starts with a | ||
`$` and should only be referenced by generated code. It is not meant for | ||
direct use. | ||
|
||
## 0.2.6 | ||
|
||
* `CheckedFromJsonException` | ||
|
@@ -29,7 +41,7 @@ | |
|
||
## 0.2.2 | ||
|
||
* Added a helper class – `$JsonMapWrapper` – and helper functions – `$wrapMap`, | ||
* Added a helper class – `$JsonMapWrapper` – and helper functions – `$wrapMap`, | ||
`$wrapMapHandleNull`, `$wrapList`, and `$wrapListHandleNull` – to support | ||
the `useWrappers` option added to `JsonSerializableGenerator` in `v0.3.0` of | ||
`package:json_serializable`. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
/// Helper function used in generated code when | ||
/// `JsonAnnotation.disallowUnregognizedKeys` is `true`. | ||
/// | ||
/// Should not be used directly. | ||
void $checkAllowedKeys(Map map, Iterable<String> allowedKeys) { | ||
if (map == null) return; | ||
var invalidKeys = map.keys.where((k) => !allowedKeys.contains(k)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might as well add Then we avoid hitting an iterator twice – which is something we should model... |
||
if (invalidKeys.isNotEmpty) { | ||
throw new UnrecognizedKeysException( | ||
new List<String>.from(invalidKeys), map, allowedKeys.toList()); | ||
} | ||
} | ||
|
||
/// Exception thrown if there is an unrecognized key in a json map that was | ||
/// provided during deserialization. | ||
class UnrecognizedKeysException implements Exception { | ||
/// The allowed keys for [map]. | ||
final List<String> allowedKeys; | ||
|
||
/// The keys from [map] that were unrecognized. | ||
final List<String> unrecognizedKeys; | ||
|
||
/// The source [Map] that the key was found in. | ||
final Map map; | ||
|
||
/// A human-readable message corresponding to the error. | ||
String get message => | ||
'Unrecognized keys [${unrecognizedKeys.join(', ')}], supported keys are ' | ||
'[${allowedKeys.join(', ')}]'; | ||
|
||
UnrecognizedKeysException(this.unrecognizedKeys, this.map, this.allowedKeys); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,13 @@ | |
|
||
/// An annotation used to specify a class to generate code for. | ||
class JsonSerializable { | ||
/// If `false` (the default), then any unrecognized keys passed to the | ||
/// generated FromJson factory will be ignored. | ||
/// | ||
/// If `true`, any unrecognized keys will be treated as an error. | ||
/// ``` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove triple-ticks? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
final bool disallowUnregognizedKeys; | ||
|
||
/// If `true` (the default), a private, static `_$ExampleFromJson` method | ||
/// is created in the generated part file. | ||
/// | ||
|
@@ -48,11 +55,13 @@ class JsonSerializable { | |
|
||
/// Creates a new [JsonSerializable] instance. | ||
const JsonSerializable( | ||
{bool createFactory: true, | ||
{bool disallowUnregognizedKeys: false, | ||
bool createFactory: true, | ||
bool createToJson: true, | ||
bool includeIfNull: true, | ||
bool nullable: true}) | ||
: this.createFactory = createFactory ?? true, | ||
: this.disallowUnregognizedKeys = disallowUnregognizedKeys ?? false, | ||
this.createFactory = createFactory ?? true, | ||
this.createToJson = createToJson ?? true, | ||
this.includeIfNull = includeIfNull ?? true, | ||
this.nullable = nullable ?? true; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -141,7 +141,7 @@ class _GeneratorHelper { | |
var mapType = _generator.anyMap ? 'Map' : 'Map<String, dynamic>'; | ||
_buffer.write('$_targetClassReference ' | ||
'${_prefix}FromJson${_genericClassArguments(true)}' | ||
'($mapType json) =>'); | ||
'($mapType json) {\n'); | ||
|
||
String deserializeFun(String paramOrFieldName, | ||
{ParameterElement ctorParam}) => | ||
|
@@ -152,10 +152,11 @@ class _GeneratorHelper { | |
if (_generator.checked) { | ||
var classLiteral = escapeDartString(_element.name); | ||
|
||
_buffer.write(''' \$checkedNew( | ||
_buffer.write(''' | ||
return \$checkedNew( | ||
$classLiteral, | ||
json, | ||
()'''); | ||
() {'''); | ||
|
||
var data = writeConstructorInvocation( | ||
_element, | ||
|
@@ -169,31 +170,28 @@ class _GeneratorHelper { | |
|
||
fieldsSetByFactory = data.usedCtorParamsAndFields; | ||
|
||
if (data.fieldsToSet.isEmpty) { | ||
// Use simple arrow syntax for the constructor invocation. | ||
// There are no fields to set | ||
_buffer.write(' => ${data.content}'); | ||
} else { | ||
// If there are fields to set, create a full function body and | ||
// create a temporary variable to hold the instance so we can make | ||
// wrapped calls to all of the fields value assignments. | ||
_buffer.write(''' { | ||
var val = '''); | ||
_buffer.write(data.content); | ||
_buffer.writeln(';'); | ||
|
||
for (var field in data.fieldsToSet) { | ||
_buffer.writeln(); | ||
var safeName = _safeNameAccess(accessibleFields[field]); | ||
_buffer.write(''' | ||
if (_annotation.disallowUnregognizedKeys) { | ||
var listLiteral = jsonLiteralAsDart( | ||
accessibleFields.values.map(_nameAccess).toList(), true); | ||
_buffer.write(''' | ||
\$checkAllowedKeys(json, $listLiteral);'''); | ||
} | ||
_buffer.write(''' | ||
var val = ${data.content};'''); | ||
|
||
for (var field in data.fieldsToSet) { | ||
_buffer.writeln(); | ||
var safeName = _safeNameAccess(accessibleFields[field]); | ||
_buffer.write(''' | ||
\$checkedConvert(json, $safeName, (v) => '''); | ||
_buffer.write('val.$field = '); | ||
_buffer.write(_deserializeForField(accessibleFields[field], | ||
checkedProperty: true)); | ||
_buffer.write(');'); | ||
} | ||
_buffer.writeln('return val; }'); | ||
_buffer.write('val.$field = '); | ||
_buffer.write(_deserializeForField(accessibleFields[field], | ||
checkedProperty: true)); | ||
_buffer.write(');'); | ||
} | ||
|
||
_buffer.writeln('return val; }'); | ||
|
||
var fieldKeyMap = new Map.fromEntries(fieldsSetByFactory | ||
.map((k) => new MapEntry(k, _nameAccess(accessibleFields[k]))) | ||
.where((me) => me.key != me.value)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Undo this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. heh, done |
||
|
@@ -206,7 +204,9 @@ class _GeneratorHelper { | |
fieldKeyMapArg = ', fieldKeyMap: $mapLiteral'; | ||
} | ||
|
||
_buffer.write('$fieldKeyMapArg)'); | ||
_buffer.write(fieldKeyMapArg); | ||
|
||
_buffer.write(')'); | ||
} else { | ||
var data = writeConstructorInvocation( | ||
_element, | ||
|
@@ -220,14 +220,25 @@ class _GeneratorHelper { | |
|
||
fieldsSetByFactory = data.usedCtorParamsAndFields; | ||
|
||
_buffer.write(' ${data.content}'); | ||
if (_annotation.disallowUnregognizedKeys) { | ||
var listLiteral = jsonLiteralAsDart( | ||
fieldsSetByFactory | ||
.map((k) => _nameAccess(accessibleFields[k])) | ||
.toList(), | ||
true); | ||
_buffer.write(''' | ||
\$checkAllowedKeys(json, $listLiteral);'''); | ||
} | ||
|
||
_buffer.write(''' | ||
return ${data.content}'''); | ||
for (var field in data.fieldsToSet) { | ||
_buffer.writeln(); | ||
_buffer.write(' ..$field = '); | ||
_buffer.write(' ..$field = '); | ||
_buffer.write(deserializeFun(field)); | ||
} | ||
} | ||
_buffer.writeln(';'); | ||
_buffer.writeln(';\n}'); | ||
_buffer.writeln(); | ||
|
||
// If there are fields that are final – that are not set via the generated | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
name: json_serializable | ||
version: 0.5.5 | ||
version: 0.5.6-dev | ||
author: Dart Team <misc@dartlang.org> | ||
description: Generates utilities to aid in serializing to/from JSON. | ||
homepage: https://github.com/dart-lang/json_serializable | ||
|
@@ -12,7 +12,7 @@ dependencies: | |
|
||
# Use a tight version constraint to ensure that a constraint on | ||
# `json_annotation`. Properly constrains all features it provides. | ||
json_annotation: '>=0.2.6 <0.2.7' | ||
json_annotation: '>=0.2.7 <0.2.8' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't you need a dep override to make tests run? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added back - this got removed when I merged master (I didn't have to add it originally so it wasn't a merge conflict.... source control is fun) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ack |
||
meta: ^1.1.0 | ||
path: ^1.3.2 | ||
source_gen: '>=0.8.1 <0.9.0' | ||
|
@@ -25,3 +25,7 @@ dev_dependencies: | |
logging: ^0.11.3+1 | ||
test: ^0.12.3 | ||
yaml: ^2.1.13 | ||
|
||
dependency_overrides: | ||
json_annotation: | ||
path: ../json_annotation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done