Seems Spring 19 wants stricter typing for aura attributes, but I’m not finding any best practices on how to approach this.
This use to work in Winter 19:
MainController.js
let myData = { parentId: "123abc", sourceData: [ { childId: "1", Some_Bool_Field__c: true }, { childId: "2", Some_Bool_Field__c: true } ] } helper.engineService(component).sendMyData( myData )
EngineService.cmp
<aura:method name="sendMyData" action="{! c.handleSendMyData }"> <aura:attribute name="data" type="Object"/> </aura:method>
EngineServiceController.js
handleSendMyData : function(component, event, helper) { var params = event.getParam("arguments"); var action = component.get("c.goGetMyData"); action.setStorable(); action.setParams({ data : params.data }); helper.dispatchAction(component, action, params); //enqueues action },
Server
@AuraEnabled public static Map<String, Object> goGetMyData(Map<String, Object> data) { // In Spring 19, we don't even see this next line System.debug('appendEngineCache data: '+data); // winter 19 use to parse these correctly Id recordId = (Id)data.get('parentId'); List<Children__c> someChildren = (List<Children__c>)data.get('sourceData'); // more }
In Spring 19, I’m not seeing any serverside debugs other than enter and immediately exit Aura with this client-side error:
“Value provided is invalid for action parameter ‘data’ of type ‘Map'”
Here’s what I’ve tried so far with no success:
- change aura attribute type
Object
toMap
(with and w/odefault="{}"
).- change serverside argument from
Map<String, Object>
toObject
and it gacksHere’s what works, but not ideal (so I’m looking for alternatives)
- Use
JSON.stringify(data)
and changing apex argument toString
then useMap<String, Object> parsedData = (Map<String, Object>)JSON.deserializedUntyped(data)
inside the method.- Then, continue to use
parsedData
in any downstream Apex.Anyone found any alternatives without that additional type coercion overhead?
EDIT: Possible solution until more info?
Given that existing unit / integration tests sometimes need to call these methods (with
Map<String, Object> parameters
), this is the least path of resistance I’ve found is to overload existing method AND useJSON.stringify
at some point in clientside.Client
action.setParams({ data : JSON.stringify(params.data) });
Server
@AuraEnabled public static Map<String, Object> goGetMyData(String data) { return goGetMyData((Map<String, Object>)JSON.deserializeUntyped(data)); } @TestVisible private static Map<String, Object> goGetMyData(Map<String, Object> data) { // all existing code // but @TestVisible added and switched over to private so aura component doesn't find the wrong one. }
Answer
Fix for this issue(W-5724071) is in the upcoming patch (scheduled to be released in mid Jan).
In Spring’19 salesforce is addressing various long standing issues with deserialization pertaining to apex actions. Brief list of enhancements include,
- Make conversion of all primitive apex data types work for positive use cases. There were a few reported issues here by the community (e.g. link).
- Make incorrect usage error out with a clear develop error. Currently any incorrect usage results in internal server error (resulting in noise for us and useless stack-id for developer)
- Add support POJO style user defined Apex types
- Make handing of SObjects consistent
- Add support for nested lists/maps
I have also reached out to documentation team to ensure more details of the enhancements get incorporated in the public docs.
Attribution
Source : Link , Question Author : tsalb , Answer Author : Emad Salman