Why do I get an Internal Salesforce.com Error when trying to pass an array of sObject values to an Apex controller action method?
I’ve posted a simple gist to demonstrate this problem to GitHub: https://gist.github.com/martyychang/76867c92f19808b6a7b7
The way to reproduce the problem is:
- Enable debug logging for yourself
- Launch oneLead.app (after you’ve created everything in the gist and tweaked the namespace references)
- Submitting a single lead works fine using the first Submit button, as expected
- Adding multiple leads and then submitting all of them using the bottom Submit button causes the Internal Salesforce.com Error
Is there something simple that I’m doing wrong? All I want to do is pass a List object as a parameter to my Apex controller from my Lightning component.
Answer
The problem is deep inside of the transport/marshalling interface layer between Lightning Components and Apex and will need to be fixed by my team.
For now I have developed a generic workaround using a small amount of Apex.
public class OneLeadController {
@AuraEnabled
public static Id createLead(Lead newLead) {
insert newLead;
return newLead.Id;
}
@AuraEnabled
public static List<Id> createLeads(String newLeads) {
List<SObject> newSObjectsList = convertJSONToListOfSObject(newLeads);
insert newSObjectsList;
List<Id> newIds = new List<Id>();
for (SObject o : newSObjectsList) {
newIds.add(o.Id);
}
return newIds;
}
@AuraEnabled
public static Lead newLead() {
return (Lead)Lead.sObjectType.newSObject(null, true);
}
private static List<SObject> convertJSONToListOfSObject(String json) {
Object[] values = (Object[])System.JSON.deserializeUntyped(json);
List<SObject> newSObjectsList = new List<SObject>();
for (Object v : values) {
Map<String, Object> m = (Map<String, Object>)v;
Schema.SObjectType targetType = Schema.getGlobalDescribe().get((String)m.get('sobjectType'));
SObject o = targetType.newSObject();
Map<String, Schema.SObjectField> fields = targetType.getDescribe().fields.getMap();
for (String fieldName : m.keySet()) {
// Filter out any psuedo fields such as LastNameLocal
Schema.SObjectField fi = fields.get(fieldName);
if (fi != null) {
if (fi.getDescribe().isCreateable() && fi.getDescribe().isUpdateable()) {
o.put(fieldName, m.get(fieldName));
}
}
}
newSObjectsList.add(o);
}
return newSObjectsList;
}
}
and a small corresponding change to the client side controller (oneLeadController.js) calling this:
({
save : function(component, event, helper) {
var self = this;
var createLeads = component.get("c.createLeads");
createLeads.setParams({
"newLeads": $A.util.json.encode(component.get("v.leads"))
});
createLeads.setCallback(self, function(a) {
if (a.getState() === "SUCCESS") {
console.log("returned: %o", a.getReturnValue());
} else {
alert($A.util.json.encode(a.getError()));
}
})
$A.enqueueAction(createLeads);
}
})
Attribution
Source : Link , Question Author : Marty C. , Answer Author : Doug Chasman