-1

So I am working with Google calendar data in the following format:

{
 "kind": "calendar#events",
 "etag": "\"thEtag\"",
 "summary": "samuel.reyes@genko.com",
 "updated": "2018-08-20T18:11:13.081Z",
 "timeZone": "America/Denver",
 "accessRole": "reader",
 "defaultReminders": [],
 "nextSyncToken": "randomblahblah",
 "items": [
  {
   "kind": "calendar#event",
   "etag": "\"etag\"",
   "id": "7q7r94v1vjoa72tq63kee",
   "status": "confirmed",
   "htmlLink": "https://www.google.com/calendar/event?eid=N3E3cjk0djF",
   "created": "2018-03-01T16:28:26.000Z",
   "updated": "2018-03-01T18:27:01.967Z",
   "summary": "Isolated Work Time - Not Available (Quiet Time)",
   "creator": {
    "email": "samuel.reyes@genko.com",
    "self": true
   },
   "organizer": {
    "email": "samuel.reyes@genko.com",
    "self": true
   },
   "start": {
    "dateTime": "2018-02-26T10:00:00-07:00",
    "timeZone": "America/Denver"
   },
   "end": {
    "dateTime": "2018-02-26T12:00:00-07:00",
    "timeZone": "America/Denver"
   },
   "recurrence": [
    "RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR"
   ],
   "iCalUID": "123455@google.com",
   "sequence": 0,
   "reminders": {
    "useDefault": true
   }
  },
  {
   "kind": "calendar#event",
   "etag": "\"etag\"",
   "id": "eventid",
   "status": "confirmed",
   "htmlLink": "https://www.google.com/calendar/event?eid=MmU4OGkxNTJmaG",
   "created": "2018-07-20T15:45:23.000Z",
   "updated": "2018-07-27T15:41:36.966Z",
   "summary": "Joe / Samuel",
   "creator": {
    "email": "joe@genko.com"
   },
   "organizer": {
    "email": "joe@genko.com"
   },
   "start": {
    "dateTime": "2018-07-26T13:30:00-06:00",
    "timeZone": "America/Denver"
   },
   "end": {
    "dateTime": "2018-07-26T14:00:00-06:00",
    "timeZone": "America/Denver"
   },
   "recurrence": [
    "RRULE:FREQ=WEEKLY;INTERVAL=2;BYDAY=TH"
   ],
   "iCalUID": "2e88i152@google.com",
   "sequence": 0,
   "attendees": [
    {
     "email": "joe@genko.com",
     "organizer": true,
     "responseStatus": "accepted"
    },
    {
     "email": "samuel.reyes@genko.com",
     "self": true,
     "responseStatus": "needsAction"
    }
   ],
   "reminders": {
    "useDefault": true
   }
  }
}, etc.... untold numbered list of such events

I have tried deserializing them into a normal Map like follows:

`Map<String, Object> m = (Map<String,Object>) JSON.deserializeUntyped(items);`

And it works fine for everything but items. Items just ends up as one long value with items as the key. And I am sure it's probably not overly complicated, but I am having a hard time figuring out how to get the items sub-object to also deserialize into some kind of usable List. To make things even more complicated, the sub-object has it's own small number of subobjects....

I went and tried to create a object structure like follows, but I don't think I've done it right, and am not figuring out how to properly deserialize it into more or less this format.

public class GoogleCalendar{
    public String kind;
    public String etag;
    public Datetime updated_date;
    public String timezone;
    public String accessRole;
    public String nextSyncToken;
    public List<GoogleCalendarItems> gcitems;
}
public class GoogleCalendarItems{
    public String index_number;
    public String kind;
    public String etag;
    public String event_id;
    public String event_status;
    public String htmlLink;
    public String created_date;
    public String updated_date;
    public String iCalUID;
    public String sequence;
    public GCI_creator creator;
    public GCI_organizer organizer;
    public ItemReminders itemReminders;
    public GCI_recurrence recurrence;
    public GCI_start start_time;
    public GCI_end end_time;
}

private class GCI_end{
    public Datetime end_time;
}
private class GCI_start{
    public Datetime start_time;
}
private class GCI_recurrence{
    public String RRULE;
}
private class ItemReminders{
    public Boolean useDefault;
}
private class GCI_organizer{
    public String organizer_email;
}
private class GCI_creator{
    public String creator_email;
}

At this point I am really tempted just to build a Nodejs application/API on Firebase, and parse the Google Calendar JSON into something usuable, and returning that to Salesforce....

I could really use some help! Even if it's just a couple of people saying "Yeah, you should probably do the Firebase route with this one..." Please/Thanks!

3

deserializeUntyped

You probably misinterpreted the data. You should have had a List<Object>, which in turn would have been a series of Map<String, Object>, etc. If you just "debug" it, it all gets squished back down into a string.

deserialize (with class)

This failed because you didn't match up the names of the fields correctly. For example, items/0/creator/email should have been just email, not creator_email. The name must be correct all the way down.

JSON2apex (a.k.a. EZ mode)

Using json2apex, you can get a parser all built for you, and then you just:

GoogleJsonWrapper wrapper = GoogleJsonWrapper.parse(jsonSource);

Here's what that output looks like. Feel free to make your own version (it also comes with a unit test!).


//
// Generated by JSON2Apex http://json2apex.herokuapp.com/
//
// The supplied json has fields with names that are not valid in apex
// and so can only be parsed with explicitly generated code, this option
// was auto selected for you.

public class GoogleJsonWrapper {

    public class Reminders {
        public Boolean useDefault {get;set;} 

        public Reminders(JSONParser parser) {
            while (parser.nextToken() != System.JSONToken.END_OBJECT) {
                if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
                    String text = parser.getText();
                    if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
                        if (text == 'useDefault') {
                            useDefault = parser.getBooleanValue();
                        } else {
                            System.debug(LoggingLevel.WARN, 'Reminders consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }

    public String kind {get;set;} 
    public String etag {get;set;} 
    public String summary {get;set;} 
    public String updated {get;set;} 
    public String timeZone {get;set;} 
    public String accessRole {get;set;} 
    public List<DefaultReminders> defaultReminders {get;set;} 
    public String nextSyncToken {get;set;} 
    public List<Items> items {get;set;} 

    public GoogleJsonWrapper(JSONParser parser) {
        while (parser.nextToken() != System.JSONToken.END_OBJECT) {
            if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
                String text = parser.getText();
                if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
                    if (text == 'kind') {
                        kind = parser.getText();
                    } else if (text == 'etag') {
                        etag = parser.getText();
                    } else if (text == 'summary') {
                        summary = parser.getText();
                    } else if (text == 'updated') {
                        updated = parser.getText();
                    } else if (text == 'timeZone') {
                        timeZone = parser.getText();
                    } else if (text == 'accessRole') {
                        accessRole = parser.getText();
                    } else if (text == 'defaultReminders') {
                        defaultReminders = arrayOfDefaultReminders(parser);
                    } else if (text == 'nextSyncToken') {
                        nextSyncToken = parser.getText();
                    } else if (text == 'items') {
                        items = arrayOfItems(parser);
                    } else {
                        System.debug(LoggingLevel.WARN, 'GoogleJsonWrapper consuming unrecognized property: '+text);
                        consumeObject(parser);
                    }
                }
            }
        }
    }

    public class Start {
        public String dateTime {get;set;} 
        public String timeZone {get;set;} 

        public Start(JSONParser parser) {
            while (parser.nextToken() != System.JSONToken.END_OBJECT) {
                if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
                    String text = parser.getText();
                    if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
                        if (text == 'dateTime') {
                            dateTime = parser.getText();
                        } else if (text == 'timeZone') {
                            timeZone = parser.getText();
                        } else {
                            System.debug(LoggingLevel.WARN, 'Start consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }

    public class Creator_Z {
        public String email {get;set;} 

        public Creator_Z(JSONParser parser) {
            while (parser.nextToken() != System.JSONToken.END_OBJECT) {
                if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
                    String text = parser.getText();
                    if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
                        if (text == 'email') {
                            email = parser.getText();
                        } else {
                            System.debug(LoggingLevel.WARN, 'Creator_Z consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }

    public class Attendees {
        public String email {get;set;} 
        public Boolean organizer {get;set;} 
        public String responseStatus {get;set;} 
        public Boolean self {get;set;} 

        public Attendees(JSONParser parser) {
            while (parser.nextToken() != System.JSONToken.END_OBJECT) {
                if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
                    String text = parser.getText();
                    if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
                        if (text == 'email') {
                            email = parser.getText();
                        } else if (text == 'organizer') {
                            organizer = parser.getBooleanValue();
                        } else if (text == 'responseStatus') {
                            responseStatus = parser.getText();
                        } else if (text == 'self') {
                            self = parser.getBooleanValue();
                        } else {
                            System.debug(LoggingLevel.WARN, 'Attendees consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }

    public class DefaultReminders {

        public DefaultReminders(JSONParser parser) {
            while (parser.nextToken() != System.JSONToken.END_OBJECT) {
                if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
                    String text = parser.getText();
                    if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
                        {
                            System.debug(LoggingLevel.WARN, 'DefaultReminders consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }

    public class Items {
        public String kind {get;set;} 
        public String etag {get;set;} 
        public String id {get;set;} 
        public String status {get;set;} 
        public String htmlLink {get;set;} 
        public String created {get;set;} 
        public String updated {get;set;} 
        public String summary {get;set;} 
        public Creator creator {get;set;} 
        public Creator organizer {get;set;} 
        public Start start {get;set;} 
        public Start end_Z {get;set;} // in json: end
        public List<String> recurrence {get;set;} 
        public String iCalUID {get;set;} 
        public Integer sequence {get;set;} 
        public Reminders reminders {get;set;} 
        public List<Attendees> attendees {get;set;} 

        public Items(JSONParser parser) {
            while (parser.nextToken() != System.JSONToken.END_OBJECT) {
                if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
                    String text = parser.getText();
                    if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
                        if (text == 'kind') {
                            kind = parser.getText();
                        } else if (text == 'etag') {
                            etag = parser.getText();
                        } else if (text == 'id') {
                            id = parser.getText();
                        } else if (text == 'status') {
                            status = parser.getText();
                        } else if (text == 'htmlLink') {
                            htmlLink = parser.getText();
                        } else if (text == 'created') {
                            created = parser.getText();
                        } else if (text == 'updated') {
                            updated = parser.getText();
                        } else if (text == 'summary') {
                            summary = parser.getText();
                        } else if (text == 'creator') {
                            creator = new Creator(parser);
                        } else if (text == 'organizer') {
                            organizer = new Creator(parser);
                        } else if (text == 'start') {
                            start = new Start(parser);
                        } else if (text == 'end') {
                            end_Z = new Start(parser);
                        } else if (text == 'recurrence') {
                            recurrence = arrayOfString(parser);
                        } else if (text == 'iCalUID') {
                            iCalUID = parser.getText();
                        } else if (text == 'sequence') {
                            sequence = parser.getIntegerValue();
                        } else if (text == 'reminders') {
                            reminders = new Reminders(parser);
                        } else if (text == 'attendees') {
                            attendees = arrayOfAttendees(parser);
                        } else {
                            System.debug(LoggingLevel.WARN, 'Items consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }

    public class Creator {
        public String email {get;set;} 
        public Boolean self {get;set;} 

        public Creator(JSONParser parser) {
            while (parser.nextToken() != System.JSONToken.END_OBJECT) {
                if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
                    String text = parser.getText();
                    if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
                        if (text == 'email') {
                            email = parser.getText();
                        } else if (text == 'self') {
                            self = parser.getBooleanValue();
                        } else {
                            System.debug(LoggingLevel.WARN, 'Creator consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }


    public static GoogleJsonWrapper parse(String json) {
        System.JSONParser parser = System.JSON.createParser(json);
        return new GoogleJsonWrapper(parser);
    }

    public static void consumeObject(System.JSONParser parser) {
        Integer depth = 0;
        do {
            System.JSONToken curr = parser.getCurrentToken();
            if (curr == System.JSONToken.START_OBJECT || 
                curr == System.JSONToken.START_ARRAY) {
                depth++;
            } else if (curr == System.JSONToken.END_OBJECT ||
                curr == System.JSONToken.END_ARRAY) {
                depth--;
            }
        } while (depth > 0 && parser.nextToken() != null);
    }







    private static List<String> arrayOfString(System.JSONParser p) {
        List<String> res = new List<String>();
        if (p.getCurrentToken() == null) p.nextToken();
        while (p.nextToken() != System.JSONToken.END_ARRAY) {
            res.add(p.getText());
        }
        return res;
    }



    private static List<Items> arrayOfItems(System.JSONParser p) {
        List<Items> res = new List<Items>();
        if (p.getCurrentToken() == null) p.nextToken();
        while (p.nextToken() != System.JSONToken.END_ARRAY) {
            res.add(new Items(p));
        }
        return res;
    }



    private static List<DefaultReminders> arrayOfDefaultReminders(System.JSONParser p) {
        List<DefaultReminders> res = new List<DefaultReminders>();
        if (p.getCurrentToken() == null) p.nextToken();
        while (p.nextToken() != System.JSONToken.END_ARRAY) {
            res.add(new DefaultReminders(p));
        }
        return res;
    }





    private static List<Attendees> arrayOfAttendees(System.JSONParser p) {
        List<Attendees> res = new List<Attendees>();
        if (p.getCurrentToken() == null) p.nextToken();
        while (p.nextToken() != System.JSONToken.END_ARRAY) {
            res.add(new Attendees(p));
        }
        return res;
    }
}
  • This is super helpful. Thanks a lot! The explanations make sense, and the website you linked is very helpful. I think with the information you've provided I should be on track to get this figured out. Thanks! – Genko Aug 20 '18 at 22:35

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.