Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 17 additions & 10 deletions json_annotation/lib/src/checked_helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,24 @@
/// `JsonSerializableGenerator.checked` is `true`.
///
/// Should not be used directly.
T $checkedNew<T>(String className, Map map, Map<String, String> fieldKeyMap,
T constructor()) {
T $checkedNew<T>(String className, Map map, T constructor(),
{Map<String, String> fieldKeyMap}) {
fieldKeyMap ??= const {};

try {
return constructor();
} on CheckedFromJsonException catch (e) {
e._className ??= className;
if (e._className == null) {
e._className = className;
assert(identical(e.map, map));
}
rethrow;
} catch (error, stack) {
throw new CheckedFromJsonException._(error, stack, map,
(error is ArgumentError) ? fieldKeyMap[error.name] : null, T,
String key;
if (error is ArgumentError) {
key = fieldKeyMap[error.name] ?? error.name;
}
throw new CheckedFromJsonException._(error, stack, map, key,
className: className);
}
}
Expand All @@ -24,13 +32,13 @@ T $checkedNew<T>(String className, Map map, Map<String, String> fieldKeyMap,
/// `JsonSerializableGenerator.checked` is `true`.
///
/// Should not be used directly.
T $checkedConvert<T>(Map map, String key, T castFunc()) {
T $checkedConvert<T>(Map map, String key, T castFunc(Object value)) {
try {
return castFunc();
return castFunc(map[key]);
} on CheckedFromJsonException {
rethrow;
} catch (error, stack) {
throw new CheckedFromJsonException._(error, stack, map, key, T);
throw new CheckedFromJsonException._(error, stack, map, key);
}
}

Expand All @@ -41,14 +49,13 @@ class CheckedFromJsonException implements Exception {
final StackTrace innerStack;
final String key;
final Map map;
final Type targetType;
final Object message;

String _className;
String get className => _className;

CheckedFromJsonException._(
this.innerError, this.innerStack, this.map, this.key, this.targetType,
this.innerError, this.innerStack, this.map, this.key,
{String className})
: _className = className,
message = _getMessage(innerError);
Expand Down
26 changes: 17 additions & 9 deletions json_serializable/lib/src/generator_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -146,15 +146,24 @@ class _GeneratorHelper {
deserializeFun);

if (_generator.checked) {
var keyFieldMap = new Map<String, String>.fromIterable(
fieldsSetByFactory,
value: (k) => _nameAccess(accessibleFields[k]));
var mapLiteral = jsonMapAsDart(keyFieldMap, true);
var fieldKeyMap = new Map.fromEntries(fieldsSetByFactory
.map((k) => new MapEntry(k, _nameAccess(accessibleFields[k])))
.where((me) => me.key != me.value));

String fieldKeyMapArg;
if (fieldKeyMap.isEmpty) {
fieldKeyMapArg = '';
} else {
var mapLiteral = jsonMapAsDart(fieldKeyMap, true);
fieldKeyMapArg = ', fieldKeyMap: $mapLiteral';
}

var classLiteral = escapeDartString(_element.displayName);

_buffer.writeln(
'${_element.displayName} ${_prefix}FromJson($mapType json) =>'
'\$checkedNew($classLiteral, json, $mapLiteral, ()=>$tempBuffer)');
'\$checkedNew($classLiteral, json, () => $tempBuffer'
'$fieldKeyMapArg)');
} else {
_buffer.writeln('${_element.name} '
'${_prefix}FromJson($mapType json) => $tempBuffer');
Expand Down Expand Up @@ -312,12 +321,11 @@ void $toJsonMapHelperName(String key, dynamic value) {
var targetType = ctorParam?.type ?? field.type;

try {
var value =
_getHelperContext(field).deserialize(targetType, 'json[$jsonKey]');
if (_generator.checked) {
return '\$checkedConvert(json, $jsonKey, () => $value)';
var value = _getHelperContext(field).deserialize(targetType, 'v');
return '\$checkedConvert(json, $jsonKey, (v) => $value)';
}
return value;
return _getHelperContext(field).deserialize(targetType, 'json[$jsonKey]');
} on UnsupportedTypeError catch (e) {
throw _createInvalidGenerationError('fromJson', field, e);
}
Expand Down
2 changes: 1 addition & 1 deletion json_serializable/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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.4 <0.2.5'
json_annotation: '>=0.2.5 <0.2.6'
meta: ^1.1.0
path: ^1.3.2
source_gen: '>=0.8.1 <0.9.0'
Expand Down
78 changes: 28 additions & 50 deletions json_serializable/test/config/build_config.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@ part of 'build_config.dart';
Config _$ConfigFromJson(Map json) => $checkedNew(
'Config',
json,
const {'builders': 'builders'},
() => new Config(
builders: $checkedConvert(
json,
'builders',
() => (json['builders'] as Map)?.map((k, e) => new MapEntry(
k as String,
(v) => (v as Map)?.map((k, e) => new MapEntry(k as String,
e == null ? null : new Builder.fromJson(e as Map))))));

abstract class _$ConfigSerializerMixin {
Expand All @@ -28,53 +26,33 @@ abstract class _$ConfigSerializerMixin {
}

Builder _$BuilderFromJson(Map json) => $checkedNew(
'Builder',
json,
const {
'import': 'import',
'target': 'target',
'isOptional': 'is_optional',
'autoApply': 'auto_apply',
'builderFactories': 'builder_factories',
'appliesBuilders': 'applies_builders',
'requiredInputs': 'required_inputs',
'buildExtentions': 'build_extensions'
},
() => new Builder(
import: $checkedConvert(json, 'import', () => json['import'] as String),
target: $checkedConvert(json, 'target', () => json['target'] as String),
isOptional: $checkedConvert(
json, 'is_optional', () => json['is_optional'] as bool),
autoApply: $checkedConvert(
json,
'auto_apply',
() => json['auto_apply'] == null
? null
: _fromJson(json['auto_apply'] as String)),
builderFactories: $checkedConvert(
json,
'builder_factories',
() => (json['builder_factories'] as List)
.map((e) => e as String)
.toList()),
appliesBuilders: $checkedConvert(
json,
'applies_builders',
() => (json['applies_builders'] as List)
?.map((e) => e as String)
?.toList()),
requiredInputs: $checkedConvert(
json,
'required_inputs',
() => (json['required_inputs'] as List)
?.map((e) => e as String)
?.toList()),
buildExtentions: $checkedConvert(
json,
'build_extensions',
() => (json['build_extensions'] as Map)?.map((k, e) => new MapEntry(
k as String,
(e as List)?.map((e) => e as String)?.toList())))));
'Builder',
json,
() => new Builder(
import: $checkedConvert(json, 'import', (v) => v as String),
target: $checkedConvert(json, 'target', (v) => v as String),
isOptional: $checkedConvert(json, 'is_optional', (v) => v as bool),
autoApply: $checkedConvert(json, 'auto_apply',
(v) => v == null ? null : _fromJson(v as String)),
builderFactories: $checkedConvert(json, 'builder_factories',
(v) => (v as List).map((e) => e as String).toList()),
appliesBuilders: $checkedConvert(json, 'applies_builders',
(v) => (v as List)?.map((e) => e as String)?.toList()),
requiredInputs: $checkedConvert(json, 'required_inputs',
(v) => (v as List)?.map((e) => e as String)?.toList()),
buildExtentions: $checkedConvert(
json,
'build_extensions',
(v) => (v as Map)?.map((k, e) => new MapEntry(k as String,
(e as List)?.map((e) => e as String)?.toList())))),
fieldKeyMap: const {
'isOptional': 'is_optional',
'autoApply': 'auto_apply',
'builderFactories': 'builder_factories',
'appliesBuilders': 'applies_builders',
'requiredInputs': 'required_inputs',
'buildExtentions': 'build_extensions'
});

abstract class _$BuilderSerializerMixin {
String get target;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,73 +11,59 @@ part of 'kitchen_sink.non_nullable.checked.dart';
// **************************************************************************

KitchenSink _$KitchenSinkFromJson(Map json) => $checkedNew(
'KitchenSink',
json,
const {
'ctorValidatedNo42': 'no-42',
'iterable': 'iterable',
'dynamicIterable': 'dynamicIterable',
'objectIterable': 'objectIterable',
'intIterable': 'intIterable',
'dateTimeIterable': 'datetime-iterable',
'dateTime': 'dateTime',
'list': 'list',
'dynamicList': 'dynamicList',
'objectList': 'objectList',
'intList': 'intList',
'dateTimeList': 'dateTimeList',
'map': 'map',
'stringStringMap': 'stringStringMap',
'dynamicIntMap': 'dynamicIntMap',
'objectDateTimeMap': 'objectDateTimeMap',
'crazyComplex': 'crazyComplex',
'val': 'val',
'writeNotNull': 'writeNotNull',
'string': r'$string',
'simpleObject': 'simpleObject'
},
() => new KitchenSink(
ctorValidatedNo42:
$checkedConvert(json, 'no-42', () => json['no-42'] as int),
iterable:
$checkedConvert(json, 'iterable', () => json['iterable'] as List),
dynamicIterable: $checkedConvert(
json, 'dynamicIterable', () => json['dynamicIterable'] as List),
objectIterable: $checkedConvert(
json, 'objectIterable', () => json['objectIterable'] as List),
intIterable: $checkedConvert(json, 'intIterable',
() => (json['intIterable'] as List).map((e) => e as int)),
dateTimeIterable: $checkedConvert(
json,
'datetime-iterable',
() => (json['datetime-iterable'] as List)
.map((e) => DateTime.parse(e as String))))
..dateTime = $checkedConvert(
json, 'dateTime', () => DateTime.parse(json['dateTime'] as String))
..list = $checkedConvert(json, 'list', () => json['list'] as List)
..dynamicList = $checkedConvert(
json, 'dynamicList', () => json['dynamicList'] as List)
..objectList =
$checkedConvert(json, 'objectList', () => json['objectList'] as List)
..intList = $checkedConvert(json, 'intList',
() => (json['intList'] as List).map((e) => e as int).toList())
..dateTimeList = $checkedConvert(
json,
'dateTimeList',
() => (json['dateTimeList'] as List)
.map((e) => DateTime.parse(e as String))
.toList())
..map = $checkedConvert(json, 'map', () => json['map'] as Map)
..stringStringMap = $checkedConvert(json, 'stringStringMap',
() => new Map<String, String>.from(json['stringStringMap'] as Map))
..dynamicIntMap =
$checkedConvert(json, 'dynamicIntMap', () => new Map<String, int>.from(json['dynamicIntMap'] as Map))
..objectDateTimeMap = $checkedConvert(json, 'objectDateTimeMap', () => (json['objectDateTimeMap'] as Map).map((k, e) => new MapEntry(k, DateTime.parse(e as String))))
..crazyComplex = $checkedConvert(json, 'crazyComplex', () => (json['crazyComplex'] as List).map((e) => (e as Map).map((k, e) => new MapEntry(k as String, (e as Map).map((k, e) => new MapEntry(k as String, (e as List).map((e) => (e as List).map((e) => DateTime.parse(e as String)).toList()).toList()))))).toList())
..val = $checkedConvert(json, 'val', () => new Map<String, bool>.from(json['val'] as Map))
..writeNotNull = $checkedConvert(json, 'writeNotNull', () => json['writeNotNull'] as bool)
..string = $checkedConvert(json, r'$string', () => json[r'$string'] as String)
..simpleObject = $checkedConvert(json, 'simpleObject', () => new SimpleObject.fromJson(json['simpleObject'] as Map)));
'KitchenSink',
json,
() => new KitchenSink(
ctorValidatedNo42: $checkedConvert(json, 'no-42', (v) => v as int),
iterable: $checkedConvert(json, 'iterable', (v) => v as List),
dynamicIterable:
$checkedConvert(json, 'dynamicIterable', (v) => v as List),
objectIterable:
$checkedConvert(json, 'objectIterable', (v) => v as List),
intIterable: $checkedConvert(
json, 'intIterable', (v) => (v as List).map((e) => e as int)),
dateTimeIterable: $checkedConvert(json, 'datetime-iterable',
(v) => (v as List).map((e) => DateTime.parse(e as String))))
..dateTime = $checkedConvert(
json, 'dateTime', (v) => DateTime.parse(v as String))
..list = $checkedConvert(json, 'list', (v) => v as List)
..dynamicList = $checkedConvert(json, 'dynamicList', (v) => v as List)
..objectList = $checkedConvert(json, 'objectList', (v) => v as List)
..intList = $checkedConvert(
json, 'intList', (v) => (v as List).map((e) => e as int).toList())
..dateTimeList = $checkedConvert(
json,
'dateTimeList',
(v) =>
(v as List).map((e) => DateTime.parse(e as String)).toList())
..map = $checkedConvert(json, 'map', (v) => v as Map)
..stringStringMap = $checkedConvert(json, 'stringStringMap',
(v) => new Map<String, String>.from(v as Map))
..dynamicIntMap = $checkedConvert(
json, 'dynamicIntMap', (v) => new Map<String, int>.from(v as Map))
..objectDateTimeMap = $checkedConvert(
json,
'objectDateTimeMap',
(v) => (v as Map)
.map((k, e) => new MapEntry(k, DateTime.parse(e as String))))
..crazyComplex = $checkedConvert(
json,
'crazyComplex',
(v) => (v as List)
.map((e) => (e as Map).map((k, e) => new MapEntry(
k as String,
(e as Map).map((k, e) =>
new MapEntry(k as String, (e as List).map((e) => (e as List).map((e) => DateTime.parse(e as String)).toList()).toList())))))
.toList())
..val = $checkedConvert(json, 'val', (v) => new Map<String, bool>.from(v as Map))
..writeNotNull = $checkedConvert(json, 'writeNotNull', (v) => v as bool)
..string = $checkedConvert(json, r'$string', (v) => v as String)
..simpleObject = $checkedConvert(json, 'simpleObject', (v) => new SimpleObject.fromJson(v as Map)),
fieldKeyMap: const {
'ctorValidatedNo42': 'no-42',
'dateTimeIterable': 'datetime-iterable',
'string': r'$string'
});

abstract class _$KitchenSinkSerializerMixin {
int get ctorValidatedNo42;
Expand Down
9 changes: 2 additions & 7 deletions json_serializable/test/yaml_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -109,17 +109,12 @@ String _prettyPrintCheckedFromJsonException(CheckedFromJsonException err) {
var message = 'Could not create `${err.className}`.';
if (yamlKey == null) {
assert(err.key == null);
message = [yamlMap.span.message(message), err.innerError].join('\n');
message = '${yamlMap.span.message(message)} ${err.innerError}';
} else {
message = '$message Unsupported value for `${err.key}`.';

if (err.targetType != dynamic &&
(err.innerError is CastError || err.innerError is TypeError)) {
message = '$message Could not convert to `${err.targetType}`.';
} else if (err.message != null) {
if (err.message != null) {
message = '$message ${err.message}';
}

message = yamlKey.span.message(message);
}

Expand Down