I have a very simple aura enabled method whose return type is map<string,List<Account>>

    public static map<string,List<Account>> getlstAccount() {        
     map<string,List<Account>> abc = new map<string,List<Account>>();

     List<Account> acconts = [select id,name from account where id in ('001r0000009eW5o','001r0000009eYuL')];
     return abc;

I just store it in a aura attribute in UI and have a button in UI which will send this data back to server, and i extract the list account back from this map and assign it to a variable of type List<Account>

attribute definition:

 <aura:attribute name="accountmap" type="map"/>
 <lightning:button variant="brand" label="Submit" onclick="{! c.handleClick }" />

Code to to get list accounts back in apex:

    public static string setlstAccount(map<string,List<Account>> abcd) {        

        List<Account> accontss = new List<Account>();
        accontss = abcd.get('accountlist');
        system.debug('accontss' + accontss);
        return 'Success';

When i click the button in UI it results in internal server error with the below message.

23:58:59:005 FATAL_ERROR System.TypeException: Invalid conversion from runtime type List<ANY> to List<Account>

Note: My use case is to implement the same for custom objects but i have simplified the code and used accounts object to help replicate the issue.

I have the below questions for this implementation

  1. Why am i not able to extract list from maps when i know the type?

  2. Whats the best way to overcome this issue?

  • Does changing accontss = abcd.get('accountlist'); to include a cast accontss = (List<Account>)abcd.get('accountlist'); help at all? I think thats the bit thats running when you click the button, right? The only other thing I can think of is the basic map type definition not storing data on the child types & causing a type failure when you call the method, since it cant match the parameter types. Where exactly is that error thrown? is there a line given? – battery.cord May 2 '18 at 18:40
  • @battery.cord, thanks for your reply. Tried accontss = (List<Account>)abcd.get('accountlist'); and the error is still the same. the line that errors is the one you asked me to change. Error thrown is 00:13:06:004 FATAL_ERROR System.TypeException: Invalid conversion from runtime type List<ANY> to List<Account> – RedDevil May 2 '18 at 18:45
  • Try these three lines: System.debug(abcd.get('accountlist') instanceof List<Account>); System.debug(abcd.get('accountlist') instanceof List<sObject>); System.debug(abcd.get('accountlist')[0] instanceof Account); The first one will 100% fail, but if you're lucky, itll know that its holding a list of sObejcts. If so, you could always iterate over the list of sObject and cast each record by adding them to a new List<Account>. If it doesn't recognize them as sObjects, you'll probably need to do some Json type casting. – battery.cord May 2 '18 at 18:48
  • 2
    Based on my experience around this, you will need to pass the records as JSON. Even though aura methods allow to accept any data type as method arguments, but during conversion, it throws internal error. It necessarily accepts everything as String. So you will need to serialize the records at JS and then deserialize it in your apex. – Jayant Das May 2 '18 at 18:53
  • 1
    I tried putting those debug, and it results in runtime errors. – Jayant Das May 2 '18 at 20:01

Even though per design, you can have aura enabled methods accept arguments of any data type, but internally the platform always treats the argument as String (and this is based on my experiences around this issue, as couldn't find any documentation for it). And if you try to use the data types in the method arguments and try to use it in your method, it always returns a runtime/internal error.

So for your issue:

  1. Why am i not able to extract list from maps when i know the type?

Because of the fact that platform never understands it that way, instead it expects it as String.

  1. Whats the best way to overcome this issue?

You need to pass the values as JSON from your JS controller (serialize/stringify) and accept those as String in your apex method and then deserialize the String. This is how you would achieve it.

In your JS controller, when passing the map, you need to stringify it as:

action.setParams({"abcd" : JSON.stringify(component.get("v.accountmap"))});

And then you need to change your apex method as below to accept the argument and deserialize it:

public static string setlstAccount(String abcd) {        
    Map<String, List<Account>> myMap = (Map<String, List<Account>>) JSON.deserialize(abcd, Map<String,List<Account>>.class);
    // all other code
    return 'Success';
  • doesnt work when i save the myMap deserialize line. this is the error Illegal assignment from Object to Map<String,List<Account>> – RedDevil May 3 '18 at 2:10
  • @RedDevil My bad, I had missed the casting there. Updated the answer, this should work now. – Jayant Das May 3 '18 at 2:19
  • Thanks this works. Will mark it as answer. Just curious to know why direct map usage doesn't work in apex. I guess only SF development team can answer that – RedDevil May 3 '18 at 2:23
  • @RedDevil - Yeah, true. I had been in exactly same situation. As mentioned by design it looks to work, but ultimately it turns out that values are passed as string only. – Jayant Das May 3 '18 at 2:25

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.