0

I am reluctant to post this -considering how many threads there are on this topic. But I am hoping a second set of eyes can help me figure out this problem here. After reading through other related problems I don't see any of the common issues like the JSON using a reserved word.

My requirement is to the Okta server and gets the user login history. This will then be displayed in a LWC data table. The callout returns a large JSON array of objects. I took the first object in the Array and placed it in JSON 2 Apex. But I am getting an Illegal value for a primitive error.

I am hoping that this post and the JSON class is not too long for this forum. So thank you in advance for taking the time to read.

Here is the JSON Class

//
// 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 OktaLoginHistory {

    public class AuthenticationContext {
        public String authenticationProvider {get;set;}
        public String credentialProvider {get;set;}
        public String credentialType {get;set;}
        public String issuer {get;set;}
        public String interface_Z {get;set;} // in json: interface
        public Integer authenticationStep {get;set;}
        public String externalSessionId {get;set;}

        public AuthenticationContext(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 == 'authenticationProvider') {
                            authenticationProvider = (String) parser.readValueAs(Object.class);
                        } else if (text == 'credentialProvider') {
                            credentialProvider = (String) parser.readValueAs(Object.class);
                        } else if (text == 'credentialType') {
                            credentialType = (String) parser.readValueAs(Object.class);
                        } else if (text == 'issuer') {
                            issuer = (String) parser.readValueAs(Object.class);
                        } else if (text == 'interface') {
                            interface_Z = (String) parser.readValueAs(Object.class);
                        } else if (text == 'authenticationStep') {
                            authenticationStep = parser.getIntegerValue();
                        } else if (text == 'externalSessionId') {
                            externalSessionId = parser.getText();
                        } else {
                            System.debug(LoggingLevel.WARN, 'AuthenticationContext consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }

    public class Geolocation {
        public Double lat {get;set;}
        public Double lon {get;set;}

        public Geolocation(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 == 'lat') {
                            lat = parser.getDoubleValue();
                        } else if (text == 'lon') {
                            lon = parser.getDoubleValue();
                        } else {
                            System.debug(LoggingLevel.WARN, 'Geolocation consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }

    public class DebugData {
        public String deviceFingerprint {get;set;}
        public String requestId {get;set;}
        public String requestUri {get;set;}
        public String threatSuspected {get;set;}
        public String url {get;set;}

        public DebugData(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 == 'deviceFingerprint') {
                            deviceFingerprint = parser.getText();
                        } else if (text == 'requestId') {
                            requestId = parser.getText();
                        } else if (text == 'requestUri') {
                            requestUri = parser.getText();
                        } else if (text == 'threatSuspected') {
                            threatSuspected = parser.getText();
                        } else if (text == 'url') {
                            url = parser.getText();
                        } else {
                            System.debug(LoggingLevel.WARN, 'DebugData consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }

    public class Request {
        public List<IpChain> ipChain {get;set;}

        public Request(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 == 'ipChain') {
                            ipChain = arrayOfIpChain(parser);
                        } else {
                            System.debug(LoggingLevel.WARN, 'Request consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }

    public Actor actor {get;set;}
    public Client client {get;set;}
    public AuthenticationContext authenticationContext {get;set;}
    public String displayMessage {get;set;}
    public String eventType {get;set;}
    public Outcome outcome {get;set;}
    public String published {get;set;}
    public SecurityContext securityContext {get;set;}
    public String severity {get;set;}
    public DebugContext debugContext {get;set;}
    public String legacyEventType {get;set;}
    public Transaction_Z transaction_Z {get;set;} // in json: transaction
    public String uuid {get;set;}
    public String version {get;set;}
    public Request request {get;set;}
    public String target {get;set;}

    public OktaLoginHistory(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 == 'actor') {
                        actor = new Actor(parser);
                    } else if (text == 'client') {
                        client = new Client(parser);
                    } else if (text == 'authenticationContext') {
                        authenticationContext = new AuthenticationContext(parser);
                    } else if (text == 'displayMessage') {
                        displayMessage = parser.getText();
                    } else if (text == 'eventType') {
                        eventType = parser.getText();
                    } else if (text == 'outcome') {
                        outcome = new Outcome(parser);
                    } else if (text == 'published') {
                        published = parser.getText();
                    } else if (text == 'securityContext') {
                        securityContext = new SecurityContext(parser);
                    } else if (text == 'severity') {
                        severity = parser.getText();
                    } else if (text == 'debugContext') {
                        debugContext = new DebugContext(parser);
                    } else if (text == 'legacyEventType') {
                        legacyEventType = parser.getText();
                    } else if (text == 'transaction') {
                        transaction_Z = new Transaction_Z(parser);
                    } else if (text == 'uuid') {
                        uuid = parser.getText();
                    } else if (text == 'version') {
                        version = parser.getText();
                    } else if (text == 'request') {
                        request = new Request(parser);
                    } else if (text == 'target') {
                        target = (String) parser.readValueAs(Object.class);
                    } else {
                        System.debug(LoggingLevel.WARN, 'OktaLoginHistory consuming unrecognized property: '+text);
                        consumeObject(parser);
                    }
                }
            }
        }
    }

    public class DebugContext {
        public DebugData debugData {get;set;}

        public DebugContext(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 == 'debugData') {
                            debugData = new DebugData(parser);
                        } else {
                            System.debug(LoggingLevel.WARN, 'DebugContext consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }

    public class Transaction_Z {
        public String type_Z {get;set;} // in json: type
        public String id {get;set;}
        public Detail detail {get;set;}

        public Transaction_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 == 'type') {
                            type_Z = parser.getText();
                        } else if (text == 'id') {
                            id = parser.getText();
                        } else if (text == 'detail') {
                            detail = new Detail(parser);
                        } else {
                            System.debug(LoggingLevel.WARN, 'Transaction_Z consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }

    public class Outcome {
        public String result {get;set;}
        public String reason {get;set;}

        public Outcome(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 == 'result') {
                            result = parser.getText();
                        } else if (text == 'reason') {
                            reason = (String) parser.readValueAs(Object.class);
                        } else {
                            System.debug(LoggingLevel.WARN, 'Outcome consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }

    public class Actor {
        public String id {get;set;}
        public String type_Z {get;set;} // in json: type
        public String alternateId {get;set;}
        public String displayName {get;set;}
        public String detailEntry {get;set;}

        public Actor(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 == 'id') {
                            id = parser.getText();
                        } else if (text == 'type') {
                            type_Z = parser.getText();
                        } else if (text == 'alternateId') {
                            alternateId = parser.getText();
                        } else if (text == 'displayName') {
                            displayName = parser.getText();
                        } else if (text == 'detailEntry') {
                            detailEntry = (String) parser.readValueAs(Object.class);
                        } else {
                            System.debug(LoggingLevel.WARN, 'Actor consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }

    public class UserAgent {
        public String rawUserAgent {get;set;}
        public String os {get;set;}
        public String browser {get;set;}

        public UserAgent(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 == 'rawUserAgent') {
                            rawUserAgent = parser.getText();
                        } else if (text == 'os') {
                            os = parser.getText();
                        } else if (text == 'browser') {
                            browser = parser.getText();
                        } else {
                            System.debug(LoggingLevel.WARN, 'UserAgent consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }

    public class SecurityContext {
        public Integer asNumber {get;set;}
        public String asOrg {get;set;}
        public String isp {get;set;}
        public String domain {get;set;}
        public Boolean isProxy {get;set;}

        public SecurityContext(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 == 'asNumber') {
                            asNumber = parser.getIntegerValue();
                        } else if (text == 'asOrg') {
                            asOrg = parser.getText();
                        } else if (text == 'isp') {
                            isp = parser.getText();
                        } else if (text == 'domain') {
                            domain = parser.getText();
                        } else if (text == 'isProxy') {
                            isProxy = parser.getBooleanValue();
                        } else {
                            System.debug(LoggingLevel.WARN, 'SecurityContext consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }

    public class GeographicalContext {
        public String city {get;set;}
        public String state {get;set;}
        public String country {get;set;}
        public String postalCode {get;set;}
        public Geolocation geolocation {get;set;}

        public GeographicalContext(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 == 'city') {
                            city = parser.getText();
                        } else if (text == 'state') {
                            state = parser.getText();
                        } else if (text == 'country') {
                            country = parser.getText();
                        } else if (text == 'postalCode') {
                            postalCode = parser.getText();
                        } else if (text == 'geolocation') {
                            geolocation = new Geolocation(parser);
                        } else {
                            System.debug(LoggingLevel.WARN, 'GeographicalContext consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }

    public class Client {
        public UserAgent userAgent {get;set;}
        public String zone {get;set;}
        public String device {get;set;}
        public String id {get;set;}
        public String ipAddress {get;set;}
        public GeographicalContext geographicalContext {get;set;}

        public Client(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 == 'userAgent') {
                            userAgent = new UserAgent(parser);
                        } else if (text == 'zone') {
                            zone = parser.getText();
                        } else if (text == 'device') {
                            device = parser.getText();
                        } else if (text == 'id') {
                            id = (String) parser.readValueAs(Object.class);
                        } else if (text == 'ipAddress') {
                            ipAddress = parser.getText();
                        } else if (text == 'geographicalContext') {
                            geographicalContext = new GeographicalContext(parser);
                        } else {
                            System.debug(LoggingLevel.WARN, 'Client consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }

    public class IpChain {
        public String ip {get;set;}
        public GeographicalContext geographicalContext {get;set;}
        public String version {get;set;}
        public String source {get;set;}

        public IpChain(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 == 'ip') {
                            ip = parser.getText();
                        } else if (text == 'geographicalContext') {
                            geographicalContext = new GeographicalContext(parser);
                        } else if (text == 'version') {
                            version = parser.getText();
                        } else if (text == 'source') {
                            source = (String) parser.readValueAs(Object.class);
                        } else {
                            System.debug(LoggingLevel.WARN, 'IpChain consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }

    public class Detail {

        public Detail(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, 'Detail consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }


    public static OktaLoginHistory parse(String json) {
        System.JSONParser parser = System.JSON.createParser(json);
        return new OktaLoginHistory(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<IpChain> arrayOfIpChain(System.JSONParser p) {
        List<IpChain> res = new List<IpChain>();
        if (p.getCurrentToken() == null) p.nextToken();
        while (p.nextToken() != System.JSONToken.END_ARRAY) {
            res.add(new IpChain(p));
        }
        return res;
    }
}

Here is the Apex method

 @AuraEnabled(Cacheable = true)
    public static Object processLoginResponse(List<String> labels, Object state){
        System.debug('in login callback');
        HttpResponse response = Continuation.getResponse(labels[0]);
        System.debug(response.getBody());
        System.debug(response.getStatusCode());
        List<OktaLoginHistory> loginHistories = (List<OktaLoginHistory>)JSON.deserialize(response.getBody(),
                List<OktaLoginHistory>.class);
        System.debug(loginHistories);
        return loginHistories;
    }

Here is a sample of the JSON the real call would return a large array of objects

{
        "actor": {
            "id": #xxxxxx",
            "type": "User",
            "alternateId": "fake.com",
            "displayName": "Brooks Johnson",
            "detailEntry": null
        },
        "client": {
            "userAgent": {
                "rawUserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36",
                "os": "Windows 10",
                "browser": "CHROME"
            },
            "zone": "null",
            "device": "Computer",
            "id": null,
            "ipAddress": "24.91.58.42",
            "geographicalContext": {
                "city": "Franklin",
                "state": "Massachusetts",
                "country": "United States",
                "postalCode": "02038",
                "geolocation": {
                    "lat": 42.08,
                    "lon": -71.4175
                }
            }
        },
         "authenticationContext": {
            "authenticationProvider": null,
            "credentialProvider": null,
            "credentialType": null,
            "issuer": null,
            "interface": null,
            "authenticationStep": 0,
            "externalSessionId": "102-gaLYsgfQdCAR3uNRdnmww"
        },
        "displayMessage": "User login to Okta",
        "eventType": "user.session.start",
        "outcome": {
            "result": "SUCCESS",
            "reason": null
        },
        "published": "2020-05-13T15:23:26.165Z",
        "securityContext": {
            "asNumber": 7922,
            "asOrg": "comcast",
            "isp": "comcast cable communications  llc",
            "domain": "comcast.net",
            "isProxy": false
        },
         "severity": "INFO",
        "debugContext": {
            "debugData": {
                "deviceFingerprint": "dc1e1c703b03c42bb730e5926cd2f692",
                "requestId": "XrwQ7Qv46w-vFVD8oDstbAAACi0",
                "requestUri": "/api/v1/authn",
                "threatSuspected": "false",
                "url": "/api/v1/authn?"
            }
        },
        "legacyEventType": "core.user_auth.login_success",
        "transaction": {
            "type": "WEB",
            "id": "XrwQ7Qv46w-vFVD8oDstbAAACi0",
            "detail": {}
        },
        "uuid": "b0de5933-952d-11ea-8343-4512e87f7043",
        "version": "0",
        "request": {
            "ipChain": [
                {
                    "ip": "24.91.58.42",
                    "geographicalContext": {
                        "city": "Franklin",
                        "state": "Massachusetts",
                        "country": "United States",
                        "postalCode": "02038",
                        "geolocation": {
                            "lat": 42.08,
                            "lon": -71.4175
                        }
                    },
                     "version": "V4",
                    "source": null
                }
            ]
        },
        "target": null
    }
5
  • 2
    Is it possible to share JSON ? Commented May 20, 2020 at 3:29
  • 1
    You're going to display this in a LWC? Why not just pass the data to the LWC and parse this in JavaScript? It's much easier to do parsing in JS than Apex to begin with.
    – sfdcfox
    Commented May 20, 2020 at 7:32
  • @salesforce-sas I added a sample of the JSON. Commented May 20, 2020 at 8:57
  • @sfdcfox I didn't know that. I assumed it would be easier to pass it back to the LWC in wrapper class. Commented May 20, 2020 at 8:58
  • 2
    Parsing in Apex is a lot slower than in JS. I would definitely not recommend doing any unnecessary server-side processing.
    – sfdcfox
    Commented May 20, 2020 at 9:02

1 Answer 1

1

Serialize your wrapper object at Apex and Pass it to LWC as

JSON.serialize(loginHistories, false)

And parse it at LWC level as

JSON.parse(receivedDataObject);
3
  • The odd thing was that I had to parse it twice for the object to work. Commented May 20, 2020 at 14:42
  • 1
    @BrooksJohnson thats because you already get json string in response.. you can directly return that to JS to parse only once. Commented May 20, 2020 at 20:35
  • Serializing the wrapper records before returning from the Apex method gives you options about whether to suppress null values or not. This ensures to get all the field keys even if they’re empty at the database level. Commented May 22, 2020 at 7:23

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .