How to deserialize JSON with escaped double quotes?
JSON(I am working with): JSONLinter confirms this is a valid JSON.
{ "errors": [ { "params": { "password": "size must be between 4 and 30", "loginId": "must match "^[a-zA-Z0-9_]*$"" } } ] }
Attempt 1(Using JSONParser:
String str = '{ "errors": [ { "params": { "password": "size must be between 4 and 30", "loginId": "must match "^[a-zA-Z0-9_]*$"" } } ] }'; JSONParser parser = JSON.createParser(str); while(parser.nextToken() != null){ parser.nextToken(); }
Fails:
▸ ERROR: System.JSONException: Unexpected character ('^' (code 94)): was ▸ expecting comma to separate OBJECT entries at input location [1,99] ▸ ERROR: Class.System.JSONParser.nextToken: line 94, column 1 ▸ AnonymousBlock: line 3, column 1 ▸
AnonymousBlock: line 3, column 1
Attempt 2(JSON2Apex option):
public class JSON2Apex { public class Errors { public Params params; } public Listerrors; public class Params { public String password; public String loginId; } } String str = '{ "errors": [ { "params": { "password": "size must be between 4 and 30", "loginId": "must match "^[a-zA-Z0-9_]*$"" } } ] }'; JSON2Apex obj = (JSON2Apex)JSON.deserialize(str, JSON2Apex.class); Fails:
▸ ERROR: System.JSONException: Unexpected character ('^' (code 94)): was ▸ expecting comma to separate OBJECT entries at [line:1, column:99] ▸ ERROR: Class.System.JSON.deserialize: line 15, column 1 ▸ AnonymousBlock: line 2, column 1 ▸ AnonymousBlock: line 2, column 1
Attempt 3(deserializeUntyped):
String str = '{ "errors": [ { "params": { "password": "size must be between 4 and 30", "loginId": "must match "^[a-zA-Z0-9_]*$"" } } ] }'; MapjsonObj = (Map Fails:)JSON.deserializeUntyped(str);
▸ ERROR: System.JSONException: Unexpected character ('^' (code 94)): was ▸ expecting comma to separate OBJECT entries at [line:1, column:99] ▸ ERROR: Class.System.JSON.deserializeUntyped: line 11, column 1 ▸ AnonymousBlock: line 2, column 1 ▸ AnonymousBlock: line 2, column 1
Attempt 4(replace the problem causing double quote in JSON):
String str = '{ "errors": [ { "params": { "password": "size must be between 4 and 30", "loginId": "must match "^[a-zA-Z0-9_]*$"" } } ] }'; MapjsonObj = (Map )JSON.deserializeUntyped(str.replaceAll('"', '\"'));
Still fails:
▸ ERROR: System.JSONException: Unexpected character ('^' (code 94)): was ▸ expecting comma to separate OBJECT entries at [line:1, column:99] ▸ ERROR: Class.System.JSON.deserializeUntyped: line 11, column 1 ▸ AnonymousBlock: line 2, column 1 ▸ AnonymousBlock: line 2, column 1
This is valid JSON.
{ "errors": [ { "params": { "password": "size must be between 4 and 30", "loginId": "must match "^[a-zA-Z0-9_]*$"" } } ] }
This is not:
String str = '{ "errors": [ { "params": { "password": "size must be between 4 and 30", "loginId": "must match "^[a-zA-Z0-9_]*$"" } } ] }';
Why? Because in Apex, backslash is an json escape character in a string literal. If you want that backslash to carry through to the in-memory representation of the string (your JSON), you must escape it in your source code:
String str = '{ "errors": [ { "params": { "password": "size must be between 4 and 30", "loginId": "must match \"^[a-zA-Z0-9_]*$\"" } } ] }';
Otherwise, Apex removes it, yielding an in-memory string that is not valid JSON because nested quote marks are not escaped:
"loginId": "must match "^[a-zA-Z0-9_]*$""
You don't need to use replaceAll() or anything fancy to fix this (and in fact, you can't - by the time you could call replaceAll(), the string's already broken and has no backslashes in it). Your logic is correct but. It's just in how you're writing string literals in your source code and that’s the reason you are struggling to deserialize JSON escape.