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);
}
})
List<String>
when doing this code and had to workaround it by converting the List to a String.