2

I am trying to parse a Json response into a custom class. The Json string looks something like this. In short it is a json with some key which is also an array of json objects.

String JSONContent = 
    '{"code": 200,' + 
        '"message": "Request response is successful",' +
        '"data": [{' + 
        '"id": "7c5fd0a3370895b6d5f7418518d7f54e",' +
        '"tracking_number": "395015527395",' + 
        '"courier_code": "taqbin-jp",' +
        '"order_number": "#1234",' + 
        '"delivery_status": "delivered",' +
        '"archived": false,' +
        '"updating": false,' + 
        '"created_at": "2022-11-11T03:39:32+00:00",' +
        '"update_date": "2022-11-11T03:40:07+00:00",' +
        '"shipping_date": null,' +
        '"customer_name": "test",' +
        '"customer_email": "[email protected]",' +
        '"customer_phone": "+1123456789",' +
        '"title": "title",' +
        '"logistics_channel": "4px channel",' +
        '"note": "check",' +
        '"destination": "LV",' +
        '"original": null,' +
        '"service_code": null,' +
        '"weight": null,' +
        '"substatus": "delivered001",' +
        '"status_info": null,' +
        '"previously": null,' +
        '"destination_track_number": null,' +
        '"exchangeNumber": null,' +
        '"consignee": null,' +
        '"scheduled_delivery_date": null,' +
        '"Scheduled_Address": null,' + 
        '"latest_event": "Delivered,2022-11-11 09:30:00",' +
        '"lastest_checkpoint_time": "2022-11-11T09:30:00+00:00",' +
        '"transit_time": 1,' +
        '"stay_time": 1,' +
        '"origin_info": {' +
        '"courier_code": "taqbin-jp",' +
        '"courier_phone": "0120 01 9625",' +
        '"weblink": "http:\\/\\/track.kuronekoyamato.co.jp\\/english\\/tracking",' +
        '"reference_number": null,' +
        '"received_date": "2022-11-10 16:24:00",' +
        '"dispatched_date": null,' +
        '"departed_airport_date": null,' +
        '"arrived_abroad_date": null,' +
        '"customs_received_date": null,' +
        '"arrived_destination_date": null,' +
        '"trackinfo": [{' +
        '"checkpoint_date": "2022-11-11 09:30:00",' +
        '"tracking_detail": "Delivered",' +
        '"location": null,' +
        '"checkpoint_delivery_status": "delivered",' +
        '"checkpoint_delivery_substatus": "delivered001"},{' + 
        '"checkpoint_date": "2022-11-11 01:56:00",' +
        '"tracking_detail": "In Transit",' +
        '"location": null,' +
        '"checkpoint_delivery_status": "transit",' +
        '"checkpoint_delivery_substatus": "transit001"},{' +
        '"checkpoint_date": "2022-11-10 16:24:00",' +
        '"tracking_detail": "Shipment Accepted",' +
        '"location": null,' +
        '"checkpoint_delivery_status": "transit",' + 
        '"checkpoint_delivery_substatus": "transit001"},{' +
        '"checkpoint_date": "2022-11-10 16:24:00",' +
        '"tracking_detail": "Shipped Out",' +
        '"location": null,' +
        '"checkpoint_delivery_status": "transit",' +
        '"checkpoint_delivery_substatus": "transit001"}],' +
        '"destination_info": {' +
        '"courier_code": null,' +
        '"courier_phone": null,' +
        '"weblink": null,' +
        '"reference_number": null,' +
        '"received_date": null,' +
        '"dispatched_date": null,' +
        '"departed_airport_date": null,' +
        '"arrived_abroad_date": null,' +
        '"customs_received_date": null,' +
        '"arrived_destination_date": null,' +
        '"trackinfo": []}}}}]}' ;

This is my class and constructor.

public class Shipments {
    public String id;
    public String tracking_number;
    public String courier_code;
    public String order_number;
    public String delivery_status;
    public String archived;
    public String updating;
    public String created_at;
    public String update_date;
    public String shipping_date;
    public String customer_name;
    public String customer_email;
    public String customer_phone;
    public String title;
    public String logistics_channel;
    public String note;
    public String destination;
    public String original;
    public String service_code;
    public String weight;
    public String substatus;
    public String status_info;
    public String previously;
    public String destination_track_number;
    public String exchangeNumber;
    public String consignee;
    public String scheduled_delivery_date;
    public String Scheduled_Address;
    public String latest_event;
    public String lastest_checkpoint_time;
    public String transit_time;
    public String stay_time;
    public String origin_info;
    public String destination_info;
    
   // Constructor 
   public Shipments(String JsonString) {
        Shipments s = (Shipments)JSON.deserialize(JsonString, List<Shipments>.class);
        System.debug(s);
   }
}
List<Object> results = (List<Object>)m.get('data');
for (Object result : results) {
    // Serialize object into JSON
    String strJSON = JSON.serialize(result);
    Shipments caseObj = new Shipments('[' + strJSON + ']');
    System.debug('[' + strJSON + ']');
}

I want the content to be parsed into the class fields. When I try to execute I get error:

System.JSONException: Illegal value for primitive.

I am not too familiar with Apex. To be honest, I am not sure if this post JSON De-serialization Issue Illegal Value for primitive is referring to the same issue or not. What did I do wrong?

1
  • Welcome to Salesforce Stack Exchange (SFSE)! Are you given one or more line numbers or more specifics in your error? When asking for help, it is almost always better to give the full exact error text along with any stack trace. [And if the error references a line number, obviously the SFSE code block does have line numbering (the numbers might not correspond even if it did), so expound a bit on the error text to indicate to us which line(s) is(are) the error line(s).]
    – Moonpie
    Commented Nov 12, 2022 at 18:25

2 Answers 2

3

@darkshadowrule is correct in his answer - in your Shipments class you need to change...

public String archived;
public String updating;

...to...

public Boolean archived;
public Boolean updating;

...in order to match what is in your JSON data.

You may also have issues with transit_time and stay_time which should likely be Integer rather than String.


Further, as I understand it, normally when you have an object (e.g., your Shipments) that contains other objects (e.g., your origin_info), you use inner classes for the contained objects.

You keep doing the same if your contained objects (e.g., your origin_info) contains other objects (e.g., your trackinfo).

And if your data is an array (e.g., your trackinfo) you use a List.

In your case it would look something like this:

public class Shipments {
    public String id;
    public String tracking_number;
    ...
    public Origin_Info origin_info;
    ...
    public Integer stay_time;

    public class Origin_Info {
        String courier_code;
        String courier_phone;
        ...
        List<TrackInfo> trackinfo;
        Destination_Info destination_info;
    }

    public class TrackInfo {
        public String checkpoint_date;
        public String tracking_detail;
        public String location;
        public String checkpoint_delivery_status;
        public String checkpoint_delivery_substatus;
    }

    public class Destination_Info {
        public String courier_code;
        ...
        List<TrackInfo> trackinfo;
    }
}

You have to watch out because you'll have a different issue if your data fields have names that are words not valid to be used in Apex.

https://json2apex.herokuapp.com/ is good at doing a lot of this for you - including dealing with any names that are not valid in Apex. You might want to just put a simple JSON into JSON2Apex and let it give you a simple class just to see what it is doing, and then feed it some more complex JSON to see how it is building it.

1
  • json2apex.herokuapp.com has indeed saved the day. This Json structure is as you said, containing lists data which further contains contained objects which also includes arrays. It has become too complicated to wrap my head around it.
    – tonywang
    Commented Nov 13, 2022 at 1:18
5

I guess the two fields are having response in Boolean and you defined it as a String, that's why it is throwing this error.

"archived": false, 
"updating": false, 

Update these two as Boolean instead of String in your class.

1
  • 2
    There are also two keys that have integer values: '"transit_time": 1,' + '"stay_time": 1,' . And check that all of the keys with null values in your example, would have string values if populated. Commented Nov 12, 2022 at 18:56

You must log in to answer this question.

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