From 02b092abcb75d5d5082618f525be63f537cc7e39 Mon Sep 17 00:00:00 2001 From: Moshe Dicker Date: Tue, 12 Mar 2024 13:52:11 -0400 Subject: [PATCH] Wrap fromJson with logging --- lib/src/open_api/callback.dart | 43 +++++----- lib/src/open_api/components.dart | 2 +- lib/src/open_api/contact.dart | 2 +- lib/src/open_api/discriminator.dart | 2 +- lib/src/open_api/encoding.dart | 2 +- lib/src/open_api/example.dart | 8 +- lib/src/open_api/external_docs.dart | 2 +- lib/src/open_api/header.dart | 3 +- lib/src/open_api/index.dart | 1 + lib/src/open_api/info.dart | 3 +- lib/src/open_api/license.dart | 2 +- lib/src/open_api/link.dart | 9 ++- lib/src/open_api/media_type.dart | 2 +- lib/src/open_api/oauth_flow.dart | 4 +- lib/src/open_api/openid_config.dart | 3 +- lib/src/open_api/operation.dart | 2 +- lib/src/open_api/parameter.dart | 8 +- lib/src/open_api/path_item.dart | 8 +- lib/src/open_api/request_body.dart | 8 +- lib/src/open_api/response.dart | 8 +- lib/src/open_api/schema.dart | 36 +++++---- lib/src/open_api/security.dart | 23 +++--- lib/src/open_api/security_scheme.dart | 2 +- lib/src/open_api/server.dart | 3 +- lib/src/open_api/server_variable.dart | 2 +- lib/src/open_api/spec.dart | 111 +++++++++++++------------- lib/src/open_api/tag.dart | 3 +- lib/src/open_api/xml.dart | 3 +- lib/src/utils/json_logging.dart | 22 +++++ 29 files changed, 184 insertions(+), 143 deletions(-) create mode 100644 lib/src/utils/json_logging.dart diff --git a/lib/src/open_api/callback.dart b/lib/src/open_api/callback.dart index 2604cb5..0d75da7 100644 --- a/lib/src/open_api/callback.dart +++ b/lib/src/open_api/callback.dart @@ -26,27 +26,28 @@ class _ApiCallbackMapConverter const _ApiCallbackMapConverter(); @override - Map fromJson(Map json) { - Map out = {}; - - for (final key in json.keys) { - final name = key; - final expression = json[key]; - if (expression is! Map) { - continue; - } - if (expression.isEmpty) { - continue; - } - out[key] = ApiCallback( - name: name, - expression: { - expression.keys.first: PathItem.fromJson(expression.values.first), - }, - ); - } - return out; - } + Map fromJson(Map json) => + fromJsonWithLogging(json, (Map json) { + Map out = {}; + + for (final key in json.keys) { + final name = key; + final expression = json[key]; + if (expression is! Map) { + continue; + } + if (expression.isEmpty) { + continue; + } + out[key] = ApiCallback( + name: name, + expression: { + expression.keys.first: PathItem.fromJson(expression.values.first), + }, + ); + } + return out; + }); @override Map toJson(Map data) { diff --git a/lib/src/open_api/components.dart b/lib/src/open_api/components.dart index b71d216..a55d5d0 100644 --- a/lib/src/open_api/components.dart +++ b/lib/src/open_api/components.dart @@ -47,5 +47,5 @@ class Components with _$Components { // ------------------------------------------ factory Components.fromJson(Map json) => - _$ComponentsFromJson(json); + fromJsonWithLogging(json, _$ComponentsFromJson); } diff --git a/lib/src/open_api/contact.dart b/lib/src/open_api/contact.dart index 3af5905..e54c8bf 100644 --- a/lib/src/open_api/contact.dart +++ b/lib/src/open_api/contact.dart @@ -21,5 +21,5 @@ class Contact with _$Contact { }) = _Contact; factory Contact.fromJson(Map json) => - _$ContactFromJson(json); + fromJsonWithLogging(json, _$ContactFromJson); } diff --git a/lib/src/open_api/discriminator.dart b/lib/src/open_api/discriminator.dart index 50e5b0e..74ce95c 100644 --- a/lib/src/open_api/discriminator.dart +++ b/lib/src/open_api/discriminator.dart @@ -16,5 +16,5 @@ class Discriminator with _$Discriminator { }) = _Discriminator; factory Discriminator.fromJson(Map json) => - _$DiscriminatorFromJson(json); + fromJsonWithLogging(json, _$DiscriminatorFromJson); } diff --git a/lib/src/open_api/encoding.dart b/lib/src/open_api/encoding.dart index 6fd4bff..14b2c71 100644 --- a/lib/src/open_api/encoding.dart +++ b/lib/src/open_api/encoding.dart @@ -13,5 +13,5 @@ class Encoding with _$Encoding { }) = _Encoding; factory Encoding.fromJson(Map json) => - _$EncodingFromJson(json); + fromJsonWithLogging(json, _$EncodingFromJson); } diff --git a/lib/src/open_api/example.dart b/lib/src/open_api/example.dart index 2d74795..e02fe4e 100644 --- a/lib/src/open_api/example.dart +++ b/lib/src/open_api/example.dart @@ -31,7 +31,7 @@ class Example with _$Example { }) = ExampleObject; factory Example.fromJson(Map json) => - _$ExampleFromJson(json); + fromJsonWithLogging(json, _$ExampleFromJson); // ------------------------------------------ // METHOD: dereference @@ -74,7 +74,7 @@ class _ExampleRefConverter implements JsonConverter { } @override - String? fromJson(String? ref) { - return ref == null ? ref : ref.split('/').last; - } + String? fromJson(String? ref) => fromJsonWithLogging(ref, (ref) { + return ref == null ? ref : ref.split('/').last; + }); } diff --git a/lib/src/open_api/external_docs.dart b/lib/src/open_api/external_docs.dart index e36a518..b919edf 100644 --- a/lib/src/open_api/external_docs.dart +++ b/lib/src/open_api/external_docs.dart @@ -17,5 +17,5 @@ class ExternalDocs with _$ExternalDocs { }) = _ExternalDocs; factory ExternalDocs.fromJson(Map json) => - _$ExternalDocsFromJson(json); + fromJsonWithLogging(json, _$ExternalDocsFromJson); } diff --git a/lib/src/open_api/header.dart b/lib/src/open_api/header.dart index e626c1b..774835b 100644 --- a/lib/src/open_api/header.dart +++ b/lib/src/open_api/header.dart @@ -15,5 +15,6 @@ class Header with _$Header { Schema? schema, }) = _Header; - factory Header.fromJson(Map json) => _$HeaderFromJson(json); + factory Header.fromJson(Map json) => + fromJsonWithLogging(json, _$HeaderFromJson); } diff --git a/lib/src/open_api/index.dart b/lib/src/open_api/index.dart index 41af83c..ede4d9a 100644 --- a/lib/src/open_api/index.dart +++ b/lib/src/open_api/index.dart @@ -4,6 +4,7 @@ import 'dart:convert'; import 'dart:io'; import 'dart:isolate'; import 'package:collection/collection.dart'; +import 'package:openapi_spec/src/utils/json_logging.dart'; import 'package:recase/recase.dart'; import 'package:yaml/yaml.dart' as yaml; import 'package:path/path.dart' as p; diff --git a/lib/src/open_api/info.dart b/lib/src/open_api/info.dart index 6808e5d..0fbc598 100644 --- a/lib/src/open_api/info.dart +++ b/lib/src/open_api/info.dart @@ -31,5 +31,6 @@ class Info with _$Info { required String version, }) = _Info; - factory Info.fromJson(Map json) => _$InfoFromJson(json); + factory Info.fromJson(Map json) => + fromJsonWithLogging(json, _$InfoFromJson); } diff --git a/lib/src/open_api/license.dart b/lib/src/open_api/license.dart index 6c0617f..48529d2 100644 --- a/lib/src/open_api/license.dart +++ b/lib/src/open_api/license.dart @@ -21,5 +21,5 @@ class License with _$License { }) = _License; factory License.fromJson(Map json) => - _$LicenseFromJson(json); + fromJsonWithLogging(json, _$LicenseFromJson); } diff --git a/lib/src/open_api/link.dart b/lib/src/open_api/link.dart index 2b10234..3af851a 100644 --- a/lib/src/open_api/link.dart +++ b/lib/src/open_api/link.dart @@ -20,7 +20,8 @@ class Link with _$Link { Map? parameters, }) = _Link; - factory Link.fromJson(Map json) => _$LinkFromJson(json); + factory Link.fromJson(Map json) => + fromJsonWithLogging(json, _$LinkFromJson); } /// Custom converter to handle schema references @@ -37,7 +38,7 @@ class _LinkRefConverter implements JsonConverter { } @override - String? fromJson(String? ref) { - return ref == null ? ref : ref.split('/').last; - } + String? fromJson(String? ref) => fromJsonWithLogging(ref, (ref) { + return ref == null ? ref : ref.split('/').last; + }); } diff --git a/lib/src/open_api/media_type.dart b/lib/src/open_api/media_type.dart index 55004ba..9623e09 100644 --- a/lib/src/open_api/media_type.dart +++ b/lib/src/open_api/media_type.dart @@ -22,5 +22,5 @@ class MediaType with _$MediaType { }) = _MediaType; factory MediaType.fromJson(Map json) => - _$MediaTypeFromJson(json); + fromJsonWithLogging(json, _$MediaTypeFromJson); } diff --git a/lib/src/open_api/oauth_flow.dart b/lib/src/open_api/oauth_flow.dart index f2cbdf2..b344c21 100644 --- a/lib/src/open_api/oauth_flow.dart +++ b/lib/src/open_api/oauth_flow.dart @@ -14,7 +14,7 @@ class OAuthFlows with _$OAuthFlows { }) = _OAuthFlows; factory OAuthFlows.fromJson(Map json) => - _$OAuthFlowsFromJson(json); + fromJsonWithLogging(json, _$OAuthFlowsFromJson); } // ========================================== @@ -49,5 +49,5 @@ class OAuthFlow with _$OAuthFlow { }) = _OAuthFlowAuthorizationCode; factory OAuthFlow.fromJson(Map json) => - _$OAuthFlowFromJson(json); + fromJsonWithLogging(json, _$OAuthFlowFromJson); } diff --git a/lib/src/open_api/openid_config.dart b/lib/src/open_api/openid_config.dart index b8df73a..5533a2e 100644 --- a/lib/src/open_api/openid_config.dart +++ b/lib/src/open_api/openid_config.dart @@ -79,5 +79,6 @@ class OpenId with _$OpenId { List? tokenEndpointAuthSigningAlgValuesSupported, }) = _OpenId; - factory OpenId.fromJson(Map json) => _$OpenIdFromJson(json); + factory OpenId.fromJson(Map json) => + fromJsonWithLogging(json, _$OpenIdFromJson); } diff --git a/lib/src/open_api/operation.dart b/lib/src/open_api/operation.dart index 030c10c..5370620 100644 --- a/lib/src/open_api/operation.dart +++ b/lib/src/open_api/operation.dart @@ -55,5 +55,5 @@ class Operation with _$Operation { }) = _Operation; factory Operation.fromJson(Map json) => - _$OperationFromJson(json); + fromJsonWithLogging(json, _$OperationFromJson); } diff --git a/lib/src/open_api/parameter.dart b/lib/src/open_api/parameter.dart index a401131..23a1e92 100644 --- a/lib/src/open_api/parameter.dart +++ b/lib/src/open_api/parameter.dart @@ -93,7 +93,7 @@ class Parameter with _$Parameter { // ------------------------------------------ factory Parameter.fromJson(Map json) => - _$ParameterFromJson(json); + fromJsonWithLogging(json, _$ParameterFromJson); // ------------------------------------------ // METHOD: dereference @@ -134,9 +134,9 @@ class _ParamRefConverter implements JsonConverter { } @override - String? fromJson(String? ref) { - return ref == null ? ref : ref.split('/').last; - } + String? fromJson(String? ref) => fromJsonWithLogging(ref, (ref) { + return ref == null ? ref : ref.split('/').last; + }); } /// Ensure that name or ref is provided diff --git a/lib/src/open_api/path_item.dart b/lib/src/open_api/path_item.dart index c9d13bc..443748b 100644 --- a/lib/src/open_api/path_item.dart +++ b/lib/src/open_api/path_item.dart @@ -58,7 +58,7 @@ class PathItem with _$PathItem { }) = _PathItem; factory PathItem.fromJson(Map json) => - _$PathItemFromJson(json); + fromJsonWithLogging(json, _$PathItemFromJson); // ------------------------------------------ // METHOD: dereference @@ -101,7 +101,7 @@ class _PathRefConverter implements JsonConverter { } @override - String? fromJson(String? ref) { - return ref == null ? ref : ref.split('/').last; - } + String? fromJson(String? ref) => fromJsonWithLogging(ref, (ref) { + return ref == null ? ref : ref.split('/').last; + }); } diff --git a/lib/src/open_api/request_body.dart b/lib/src/open_api/request_body.dart index 397f3c5..bff7952 100644 --- a/lib/src/open_api/request_body.dart +++ b/lib/src/open_api/request_body.dart @@ -33,7 +33,7 @@ class RequestBody with _$RequestBody { /// Construct an instance of [RequestBody] from a JSON map factory RequestBody.fromJson(Map json) => - _$RequestBodyFromJson(json); + fromJsonWithLogging(json, _$RequestBodyFromJson); // ------------------------------------------ // METHOD: dereference @@ -72,7 +72,7 @@ class _RequestRefConverter implements JsonConverter { } @override - String? fromJson(String? ref) { - return ref == null ? ref : ref.split('/').last; - } + String? fromJson(String? ref) => fromJsonWithLogging(ref, (ref) { + return ref == null ? ref : ref.split('/').last; + }); } diff --git a/lib/src/open_api/response.dart b/lib/src/open_api/response.dart index 75fbf2e..75482aa 100644 --- a/lib/src/open_api/response.dart +++ b/lib/src/open_api/response.dart @@ -39,7 +39,7 @@ class Response with _$Response { // ------------------------------------------ factory Response.fromJson(Map json) => - _$ResponseFromJson(json); + fromJsonWithLogging(json, _$ResponseFromJson); // ------------------------------------------ // METHOD: dereference @@ -81,7 +81,7 @@ class _ResponseRefConverter implements JsonConverter { } @override - String? fromJson(String? ref) { - return ref == null ? ref : ref.split('/').last; - } + String? fromJson(String? ref) => fromJsonWithLogging(ref, (ref) { + return ref == null ? ref : ref.split('/').last; + }); } diff --git a/lib/src/open_api/schema.dart b/lib/src/open_api/schema.dart index 9ce15d9..e74261b 100644 --- a/lib/src/open_api/schema.dart +++ b/lib/src/open_api/schema.dart @@ -234,7 +234,8 @@ class Schema with _$Schema { // ------------------------------------------ /// Convert from JSON representation - factory Schema.fromJson(Map json) => _$SchemaFromJson(json); + factory Schema.fromJson(Map json) => + fromJsonWithLogging(json, _$SchemaFromJson); // ------------------------------------------ // METHOD: dereference @@ -412,9 +413,9 @@ class _SchemaRefConverter implements JsonConverter { } @override - String? fromJson(String? ref) { - return ref == null ? ref : ref.split('/').last; - } + String? fromJson(String? ref) => fromJsonWithLogging(ref, (ref) { + return ref == null ? ref : ref.split('/').last; + }); } // ========================================== @@ -449,11 +450,13 @@ class _SchemaConverter implements JsonConverter> { @override Schema fromJson(Map json) { - if (json.containsKey('enum') && json['enum'].isNotEmpty) { - return _SchemaEnum.fromJson(json); - } else { - return Schema.fromJson(json); - } + return fromJsonWithLogging(json, (json) { + if (json.containsKey('enum') && json['enum'].isNotEmpty) { + return _SchemaEnum.fromJson(json); + } else { + return Schema.fromJson(json); + } + }); } } @@ -468,11 +471,13 @@ class _SchemaMapConverter @override Map fromJson(Map json) { - Map out = {}; - for (final key in json.keys) { - out[key] = _SchemaConverter().fromJson(json[key]); - } - return out; + return fromJsonWithLogging(json, (json) { + Map out = {}; + for (final key in json.keys) { + out[key] = _SchemaConverter().fromJson(json[key]); + } + return out; + }); } @override @@ -497,7 +502,8 @@ class _SchemaListConverter @override List fromJson(List json) { return json - .map((e) => _SchemaConverter().fromJson(Map.from(e))) + .map((e) => fromJsonWithLogging( + Map.from(e), _SchemaConverter().fromJson)) .toList(); } diff --git a/lib/src/open_api/security.dart b/lib/src/open_api/security.dart index 0010235..a4cb0d3 100644 --- a/lib/src/open_api/security.dart +++ b/lib/src/open_api/security.dart @@ -20,17 +20,18 @@ class Security with _$Security { @Default([]) List scopes, }) = _Security; - factory Security.fromJson(Map json) { - if (json.isEmpty) { - return const Security(); - } else { - final name = json.keys.first; - return Security( - name: name, - scopes: List.from(json[name] ?? []), - ); - } - } + factory Security.fromJson(Map json) => + fromJsonWithLogging(json, (json) { + if (json.isEmpty) { + return const Security(); + } else { + final name = json.keys.first; + return Security( + name: name, + scopes: List.from(json[name] ?? []), + ); + } + }); Map toJson() { if (name == null) { diff --git a/lib/src/open_api/security_scheme.dart b/lib/src/open_api/security_scheme.dart index a4da6d2..7f73a47 100644 --- a/lib/src/open_api/security_scheme.dart +++ b/lib/src/open_api/security_scheme.dart @@ -95,5 +95,5 @@ class SecurityScheme with _$SecurityScheme { // ------------------------------------------ factory SecurityScheme.fromJson(Map json) => - _$SecuritySchemeFromJson(json); + fromJsonWithLogging(json, _$SecuritySchemeFromJson); } diff --git a/lib/src/open_api/server.dart b/lib/src/open_api/server.dart index 380550d..a33c8d9 100644 --- a/lib/src/open_api/server.dart +++ b/lib/src/open_api/server.dart @@ -22,5 +22,6 @@ class Server with _$Server { final Map? variables, }) = _Server; - factory Server.fromJson(Map json) => _$ServerFromJson(json); + factory Server.fromJson(Map json) => + fromJsonWithLogging(json, _$ServerFromJson); } diff --git a/lib/src/open_api/server_variable.dart b/lib/src/open_api/server_variable.dart index dc1cd2c..b258947 100644 --- a/lib/src/open_api/server_variable.dart +++ b/lib/src/open_api/server_variable.dart @@ -23,5 +23,5 @@ class ServerVariable with _$ServerVariable { }) = _ServerVariable; factory ServerVariable.fromJson(Map json) => - _$ServerVariableFromJson(json); + fromJsonWithLogging(json, _$ServerVariableFromJson); } diff --git a/lib/src/open_api/spec.dart b/lib/src/open_api/spec.dart index 7b3408b..7ed6d51 100644 --- a/lib/src/open_api/spec.dart +++ b/lib/src/open_api/spec.dart @@ -169,63 +169,66 @@ class OpenApi with _$OpenApi { // ------------------------------------------ /// Create an [OpenApi] object from a JSON representation of an OpenAPI - factory OpenApi.fromJson(Map json) { - // Initialize the schemas, will be formatted in place below - Map schemas = json['components']?['schemas'] ?? {}; - final d = _formatSpecFromJson( - json: json, - schemas: schemas, - ); + factory OpenApi.fromJson(Map json) => + fromJsonWithLogging(json, (json) { + // Initialize the schemas, will be formatted in place below + Map schemas = json['components']?['schemas'] ?? {}; + final d = _formatSpecFromJson( + json: json, + schemas: schemas, + ); - // Search for any extra schemas created by this generator - // Used to improve the generated schema library - schemas = d['components']?['schemas'] ?? {}; - final Map schemaExtra = {}; - final Map> extraSchemaMapping = {}; - for (final s in schemas.keys) { - final (schemaOut, extraOut) = _extraComponentSchemas( - schemaKey: s, - schemaMap: schemas[s], - allSchemaNames: (schemas.keys.toList() + schemaExtra.keys.toList()), - ); - schemas[s] = schemaOut; - if (extraOut.isNotEmpty) { - schemaExtra.addAll(extraOut); - extraSchemaMapping[s] = extraOut.keys.toList(); - } - } - // Add any extra schemas to the spec - schemas.addAll(schemaExtra); - if (schemas.isNotEmpty) { - d['components']?['schemas'] = schemas; - } + // Search for any extra schemas created by this generator + // Used to improve the generated schema library + schemas = d['components']?['schemas'] ?? {}; + final Map schemaExtra = {}; + final Map> extraSchemaMapping = {}; + for (final s in schemas.keys) { + final (schemaOut, extraOut) = _extraComponentSchemas( + schemaKey: s, + schemaMap: schemas[s], + allSchemaNames: (schemas.keys.toList() + schemaExtra.keys.toList()), + ); + schemas[s] = schemaOut; + if (extraOut.isNotEmpty) { + schemaExtra.addAll(extraOut); + extraSchemaMapping[s] = extraOut.keys.toList(); + } + } + // Add any extra schemas to the spec + schemas.addAll(schemaExtra); + if (schemas.isNotEmpty) { + d['components']?['schemas'] = schemas; + } - final out = OpenApi( - version: d.containsKey('openapi') ? d['openapi'] : null, - info: Info.fromJson(d['info']), - jsonSchemaDialect: d['jsonSchemaDialect'], - externalDocs: d.containsKey('externalDocs') - ? ExternalDocs.fromJson(d['externalDocs']) - : null, - servers: (d['servers'] as List?) - ?.map((e) => Server.fromJson(e)) - .toList(), - tags: (d['tags'] as List?)?.map((e) => Tag.fromJson(e)).toList(), - paths: (d['paths'] as Map?) - ?.map((k, e) => MapEntry(k, PathItem.fromJson(e))), - webhooks: (d['webhooks'] as Map?) - ?.map((k, e) => MapEntry(k, PathItem.fromJson(e))), - components: d.containsKey('components') - ? Components.fromJson(d['components']) - : null, - security: (d['security'] as List?) - ?.map((e) => Security.fromJson(e)) - .toList(), - extraSchemaMapping: extraSchemaMapping, - ); + final out = OpenApi( + version: d.containsKey('openapi') ? d['openapi'] : null, + info: Info.fromJson(d['info']), + jsonSchemaDialect: d['jsonSchemaDialect'], + externalDocs: d.containsKey('externalDocs') + ? ExternalDocs.fromJson(d['externalDocs']) + : null, + servers: (d['servers'] as List?) + ?.map((e) => Server.fromJson(e)) + .toList(), + tags: (d['tags'] as List?) + ?.map((e) => Tag.fromJson(e)) + .toList(), + paths: (d['paths'] as Map?) + ?.map((k, e) => MapEntry(k, PathItem.fromJson(e))), + webhooks: (d['webhooks'] as Map?) + ?.map((k, e) => MapEntry(k, PathItem.fromJson(e))), + components: d.containsKey('components') + ? Components.fromJson(d['components']) + : null, + security: (d['security'] as List?) + ?.map((e) => Security.fromJson(e)) + .toList(), + extraSchemaMapping: extraSchemaMapping, + ); - return out; - } + return out; + }); // ------------------------------------------ // METHOD: toJson diff --git a/lib/src/open_api/tag.dart b/lib/src/open_api/tag.dart index 54c64e8..92933a9 100644 --- a/lib/src/open_api/tag.dart +++ b/lib/src/open_api/tag.dart @@ -22,5 +22,6 @@ class Tag with _$Tag { ExternalDocs? externalDocs, }) = _Tag; - factory Tag.fromJson(Map json) => _$TagFromJson(json); + factory Tag.fromJson(Map json) => + fromJsonWithLogging(json, _$TagFromJson); } diff --git a/lib/src/open_api/xml.dart b/lib/src/open_api/xml.dart index 74b3850..6b7c348 100644 --- a/lib/src/open_api/xml.dart +++ b/lib/src/open_api/xml.dart @@ -25,5 +25,6 @@ class Xml with _$Xml { bool? wrapped, }) = _Xml; - factory Xml.fromJson(Map json) => _$XmlFromJson(json); + factory Xml.fromJson(Map json) => + fromJsonWithLogging(json, _$XmlFromJson); } diff --git a/lib/src/utils/json_logging.dart b/lib/src/utils/json_logging.dart new file mode 100644 index 0000000..6c5371e --- /dev/null +++ b/lib/src/utils/json_logging.dart @@ -0,0 +1,22 @@ +/// Wraps a function that parses a JSON map to a specific type and logs any errors that occur during parsing. +T fromJsonWithLogging(B json, T Function(B) getJson) { + try { + return getJson(json); + } catch (e) { + if (e is _ParsingJsonException) { + rethrow; + } else { + // ignore: avoid_print + throw _ParsingJsonException("Failed to parse $T: $json\n$e"); + } + } +} + +/// A custom exception that is thrown when a JSON parsing error occurs. +/// This is used so only invalid JSON parsing errors are caught and logged. +class _ParsingJsonException implements Exception { + final String message; + _ParsingJsonException(this.message); + @override + String toString() => message; +}