5

I have a JSON string that I want to parse out. I have use the below code many times but for whatever reason this time it is not working. Can anyone poke any holes in this logic? Or point out why this may not be the best way to parse through a string?

String tokencred = [{"Id":"003m000000yKLySkkL","Token":"I2j5bUky04B4eLJGYELV"}]

    JSONParser parser = JSON.createParser(tokencred);
    //parse and map the returned string
    while (parser.nextToken() != null) {
        String parsedId;
        String parsedToken;
        if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'Id')) {
            parser.nextToken();
            parsedId = parser.getText();
        }
        if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'Token')) {
            parser.nextToken();
            parsedToken = parser.getText();
        }
        tokenCredMap.put(parsedId,parsedToken);
    }
    system.debug('tokenCredMap:: ' + tokenCredMap);

14:31:15.0 (808193208)|USER_DEBUG|[153]|DEBUG|tokenCredMap:: {null=null, 003m000000yKLySkkL=null}

I do need the map as there is additional logic that will enable me to have multiple token/id combos.

UPDATE:

15:02:55.11 (726597242)|USER_DEBUG|[314]|DEBUG|this is the updated value [{"Id":"00Qm0000009qqdiEAA","Token":"J5h8yz004mFJi44ozuhw"}]
15:02:55.11 (727270334)|USER_DEBUG|[323]|DEBUG|fieldName: Id
15:02:55.11 (727412370)|USER_DEBUG|[323]|DEBUG|fieldName: Token
15:02:55.11 (727597218)|USER_DEBUG|[342]|DEBUG|tokenCredMap:: {null=null, 00Qm0000009qqdiEAA=null}
15:02:55.11 (732474914)|DML_BEGIN|[360]|Op:Update|Type:Lead|Rows:1
  • "why this may not be the best way to parse through a string" - because JSON.deserializeUntyped in this case is much easier :) – Eric Sep 6 '18 at 2:41
5

I think the issue is that you are not advancing the parser after saving the ParsedId. Let's say that the if statement for the Id is evaluated as true. You then save the ParsedId, but you are not advancing the parser forward afterwords. That means the second If statement can never be true because the parser is still pointing to the value of the Id.

| improve this answer | |
  • 2
    This is the most direct answer to the question. – gNerb Sep 5 '18 at 22:06
  • Yep I agree with gNerb about that. – Keith C Sep 5 '18 at 22:10
  • @Hans Shouldn't the while loop allow the parser to loop through all the values thus allowing it to see the token value? – Olivia Sep 6 '18 at 14:32
  • It does get through all the values, but you're re-declaring both values on each loop. I believe this is overwriting whatever you got from the previous loop. for example, if you got the Id on the first loop, you add it to the map with a null value pair (Since we haven't found the token yet). When we loop the next time, both values are re-initialized to null. When we get the token this loop, the Id is now null so a null key is added to the map with the value of the token I believe – Hans Donkersloot Sep 6 '18 at 14:36
3

If would write that like this:

Map<String, String> tokenCredMap = new Map<String, String>();
String tokencred = '[{"Id":"003m000000yKLySkkL","Token":"I2j5bUky04B4eLJGYELV"}]';

List<Object> items = (List<Object>) JSON.deserializeUntyped(tokencred);

for (object item : items) {
    Map<String, Object> typedItem = (Map<String, Object>) item;
    tokenCredMap.put((Id) typedItem.get('Id'), (String) typedItem.get('Token'));
}
system.debug('tokenCredMap:: ' + tokenCredMap);

as it leaves working at the token level to the deserializeUntyped method and so avoids the risk of bugs in that area.

(In your code often both parsedId and parsedToken will be null and if other attributes were in the JSON your code would be tripped up. Also in JSON the order of the attributes is meant to be open and your logic requires the attributes to be in a specific order.)

| improve this answer | |
  • This is the best answer (posted so far) although it doesn't explain why what the OP is doing doesn't work. I was in the process of writing an answer that combined both of the answers that were just posted but figured not much point anymore :P) – gNerb Sep 5 '18 at 22:07
  • 1
    @gNerb Yeah I think Hans is describing the core problem and I'm just commenting how fragile in general a hand-written parser is. – Keith C Sep 5 '18 at 22:09
  • this is great. thank you for posting a different look at parsing. Unfortunately it is still not parsing out the token for what ever reason. What confuses me is: if there was another process that was rolling it back then the ID wouldn't be saved to the map, right? I will update my post with the results from your solution. – Olivia Sep 5 '18 at 22:09
  • @Olivia The best way to develop logic like this is to use a unit test so you can debug a simple case. – Keith C Sep 5 '18 at 22:12
  • Keith I had a hard time getting your sample to work due to some run time type conversion errors. I updated your code with a working sample. Hope you don't mind. – gNerb Sep 5 '18 at 22:17
0

I found the issue: the parsedId and the parsedToken need to be on the outside of the loop. This is another way to loop through the parser that I found and it is working:

    String parsedId;
    String parsedToken;
    while (parser.nextToken() != null) {
        if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
            String fieldName = parser.getText();
            System.debug('fieldName: ' + fieldName);
            //move to token after the field name
            parser.nextToken();
            if (fieldName == 'Id') {
                parsedId = parser.getText();
            } else if (fieldName == 'Token') {
                parsedToken = parser.getText();
            }
        }
        tokenCredMap.put(parsedId,parsedToken);
    }
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.