[SalesForce] System.JSONException when deserializing JSON to object

note : this is a follow up to this question

I'm following the approach on this post, and have created a class to use to deserialize a json string as I know the structure of the response.

I am able to deserialize the json to a map<string,decimal> but I receive an error if I try to deserialize to a list of an inner class that consists of a string and a decimal:

public class CurrentRate {
    string IsoCode;
    decimal value;
}

here is the structure of my JSON class, with the portion that doesnt work commented out:

public class myJSONClass{
    public string disclaimer;
    public string license;
    public string timestamp;
    public string base;
    // public currentRate[] rates;
    public map<string,decimal> rates = new map<string,decimal>();
}

The JSON being parsed is structured as follows

{
    "disclaimer": "Usage subject to terms: https://openexchangerates.org/terms",
    "license": "https://openexchangerates.org/license",
    "timestamp": 1506733203,
    "base": "USD",
    "rates": {
        "AED": 3.672611,
        "AFN": 68.671,
        "ALL": 113.870562,
        "AMD": 478.245,
        "ANG": 1.779798
   }
}

The deserialization is happening here:

string responseText = res.getBody();           
myJSONClass obj = (myJSONClass)JSON.deserialize(responseText, myJSONClass.class);   

And the error is:

System.JSONException: Expected List but
found { at [line:5, column:16]

And here is the full code in case its helpful. I can work with the map, but it seems like I should be able to deserialize to a list and I want to know what I am doing wrong.

public class CurrencyUpdater {

    public class CurrentRate {
            string IsoCode;
            decimal value;
    }

    public class myJSONClass {
        public string disclaimer;
        public string license;
        public string timestamp;
        public string base;
        // does not work        public currentRate[] rates;
        public map<string,decimal> rates = new map<string,decimal>();
    }

    public list<CurrentRate> callEndpoint() {

          list<currentRate> OERRates = new list<currentRate>();   

          HttpRequest req = new HttpRequest();         
          req.setMethod('GET');
          req.setEndpoint('callout:OpenExchangeRates');                
          Http http = new Http();

          try {
              HTTPResponse res = http.send(req);                          
              string responseText = res.getBody();
              system.debug('responseText = ' + responseText);

              myJSONClass obj = (myJSONClass)JSON.deserialize(responseText, myJSONClass.class);   
              system.debug(obj.rates.keySet());                              

          } catch(System.CalloutException e) {

          }

         return OERRates;                       
    } 
}

Best Answer

To deserialize it as a list, you'd have to change your JSON:

"rates": [
    { "IsoCode": "AED", "value": 3.672611 },
    { "IsoCode": "AFN", "value": 68.671 },
    { "IsoCode": "ALL", "value": 113.870562 },
    { "IsoCode": "AMD", "value": 478.245 },
    { "IsoCode": "ANG", "value": 1.779798 }
  ]

At this point the currentRate[] would be the correct data type. If you can't change the JSON, then Map<String, Decimal> is your best alternative, assuming you don't want to enumerate all the possible currency codes that you may receive.