|
1 | 1 | import 'package:flutter_policy_engine/src/exceptions/json_parse_exception.dart';
|
2 | 2 | import 'package:flutter_policy_engine/src/exceptions/json_serialize_exception.dart';
|
3 | 3 | import 'package:flutter_policy_engine/src/utils/log_handler.dart';
|
| 4 | +import 'dart:convert'; |
4 | 5 |
|
5 | 6 | /// Utility for type-safe JSON conversions with generic support.
|
6 | 7 | ///
|
@@ -262,4 +263,102 @@ class JsonHandler {
|
262 | 263 | return null;
|
263 | 264 | }
|
264 | 265 | }
|
| 266 | + |
| 267 | + /// Parses a JSON string into a Map<String, dynamic> with comprehensive error handling. |
| 268 | + /// |
| 269 | + /// This function safely converts a JSON string representation into a strongly-typed |
| 270 | + /// map structure. It includes validation to ensure the parsed result is actually |
| 271 | + /// a map and provides detailed error information for debugging. |
| 272 | + /// |
| 273 | + /// The function handles various error scenarios: |
| 274 | + /// - Invalid JSON syntax |
| 275 | + /// - JSON that doesn't represent an object (e.g., arrays, primitives) |
| 276 | + /// - Empty or null input strings |
| 277 | + /// |
| 278 | + /// Returns a [Map<String, dynamic>] containing the parsed JSON data. |
| 279 | + /// |
| 280 | + /// Throws [JsonParseException] if the JSON string cannot be parsed or doesn't |
| 281 | + /// represent a valid JSON object. |
| 282 | + /// |
| 283 | + /// Example usage: |
| 284 | + /// ```dart |
| 285 | + /// try { |
| 286 | + /// final jsonString = '{"name": "John", "age": 30}'; |
| 287 | + /// final result = JsonHandler.parseJsonString(jsonString); |
| 288 | + /// print(result['name']); // Output: John |
| 289 | + /// } catch (e) { |
| 290 | + /// print('Failed to parse JSON: $e'); |
| 291 | + /// } |
| 292 | + /// ``` |
| 293 | + static Map<String, dynamic> parseJsonString( |
| 294 | + String jsonString, { |
| 295 | + String? context, |
| 296 | + }) { |
| 297 | + LogHandler.debug( |
| 298 | + 'Starting JSON string parsing', |
| 299 | + context: { |
| 300 | + 'input_length': jsonString.length, |
| 301 | + 'context': context ?? 'unknown', |
| 302 | + }, |
| 303 | + operation: 'json_parse_string', |
| 304 | + ); |
| 305 | + |
| 306 | + try { |
| 307 | + // Validate input |
| 308 | + if (jsonString.isEmpty) { |
| 309 | + throw JsonParseException( |
| 310 | + 'Cannot parse empty JSON string', |
| 311 | + ); |
| 312 | + } |
| 313 | + |
| 314 | + // Parse JSON string |
| 315 | + final dynamic parsed = jsonDecode(jsonString); |
| 316 | + |
| 317 | + // Validate that the parsed result is a map |
| 318 | + if (parsed is! Map<String, dynamic>) { |
| 319 | + throw JsonParseException( |
| 320 | + 'JSON string does not represent a valid object. ' |
| 321 | + 'Expected Map<String, dynamic>, got ${parsed.runtimeType}', |
| 322 | + originalError: TypeError(), |
| 323 | + ); |
| 324 | + } |
| 325 | + |
| 326 | + LogHandler.debug( |
| 327 | + 'Successfully parsed JSON string', |
| 328 | + context: { |
| 329 | + 'parsed_keys_count': parsed.length, |
| 330 | + 'context': context ?? 'unknown', |
| 331 | + }, |
| 332 | + operation: 'json_parse_string_success', |
| 333 | + ); |
| 334 | + |
| 335 | + return parsed; |
| 336 | + } catch (e, stackTrace) { |
| 337 | + final errorMessage = 'Failed to parse JSON string: ${e.toString()}'; |
| 338 | + |
| 339 | + LogHandler.error( |
| 340 | + errorMessage, |
| 341 | + error: e, |
| 342 | + stackTrace: stackTrace, |
| 343 | + context: { |
| 344 | + 'input_length': jsonString.length, |
| 345 | + 'input_preview': jsonString.length > 100 |
| 346 | + ? '${jsonString.substring(0, 100)}...' |
| 347 | + : jsonString, |
| 348 | + 'context': context ?? 'unknown', |
| 349 | + }, |
| 350 | + operation: 'json_parse_string_error', |
| 351 | + ); |
| 352 | + |
| 353 | + // Re-throw as JsonParseException if it's not already |
| 354 | + if (e is JsonParseException) { |
| 355 | + rethrow; |
| 356 | + } |
| 357 | + |
| 358 | + throw JsonParseException( |
| 359 | + errorMessage, |
| 360 | + originalError: e, |
| 361 | + ); |
| 362 | + } |
| 363 | + } |
265 | 364 | }
|
0 commit comments