Cómo deserializar la lista con map to wrapperclass
Tengo una cadena que estoy tratando de deserializar en un contenedor / clase de objeto. Pero obtén el error:
Expected Map<String,String> but found [line:1, column:3]
Wrapperclass
global class Invocable_Obj_HandleInvoice {
@AuraEnabled global Id invoiceId;
@AuraEnabled global string invoiceNumber;
@AuraEnabled global decimal balanceAmount;
@AuraEnabled global decimal totalAmount;
@AuraEnabled global string customerName;
@AuraEnabled global string zuoraStatus;
@AuraEnabled global string handlingStatus;
@AuraEnabled global string selectedOption;
@AuraEnabled global Map<String, String> availableOptions;
}
Cuerda
[
{
"availableOptions": [
{
"key": "e",
"value": "f"
},
{
"key": "g",
"value": "z"
}
],
"balanceAmount": -100,
"customerName": "Test",
"handlingStatus": "New",
"invoiceId": "a0S2o000023CSHoEAO",
"invoiceNumber": "INV-001",
"selectedOption": "A",
"totalAmount": -100,
"zuoraStatus": "Posted"
},
{
"availableOptions": [
{
"key": "a",
"value": "x"
},
{
"key": "b",
"value": "y"
},
{
"key": "c",
"value": "z"
}
],
"balanceAmount": -100,
"customerName": "Test",
"handlingStatus": "New",
"invoiceId": "a0S2o000023CSHoEAO",
"invoiceNumber": "INV-001",
"selectedOption": "y",
"totalAmount": -100,
"zuoraStatus": "Posted"
}
]
Apéndice
system.debug((List<Invocable_Obj_HandleInvoice>) System.JSON.deserialize(invoices, List<Invocable_Obj_HandleInvoice>.class));
Lista pasada al componente relámpago
List<Invocable_Obj_HandleInvoice> hiList = new List<Invocable_Obj_HandleInvoice>();
Invocable_Obj_HandleInvoice hi1 = new Invocable_Obj_HandleInvoice();
hi1.invoiceId = zi[0].id;
hi1.invoiceNumber = zi[0].Name;
hi1.balanceAmount = zi[0].Zuora__Balance2__c;
hi1.totalAmount = zi[0].Zuora__TotalAmount__c;
hi1.customerName = 'Test';
hi1.zuoraStatus = zi[0].Zuora__Status__c;
hi1.handlingStatus = zi[0].Handling_Status__c;
hi1.selectedOption = 'A';
hi1.availableOptions = new Map<String,string> {'e'=>'f', 'g'=> 'z'};
hiList.add(hi1);
return hiList;
Controlador de rayos
var act = cmp.get("c.updateInvoices");
var updatedInvoiceList = JSON.stringify(cmp.get('v.handleInvoices'));
act.setParams({ "invoices" : updatedInvoiceList});
$A.enqueueAction(act);
Componente <aura: atributo type = "List" name = "handleInvoices" />
Controlador de rayos
doInit : function(cmp, event, helper) {
var action = cmp.get("c.testHandlInvoice");
action.setCallback(this, function(response) {
var state = response.getState();
if (state === "SUCCESS") {
cmp.set('v.handleInvoices', response.getReturnValue());
console.log(cmp.get('v.handleInvoices'));
}
});
$A.enqueueAction(action);
},
console.log
availableOptions: Array(3)
0: {key: "a", value: "x"}
1: {key: "b", value: "y"}
2: {key: "c", value: "z"}
length: 3
__proto__: Array(0)
balanceAmount: -100
customerName: "Test"
handlingStatus: "New"
invoiceId: "a0S2o000023CSHoEAO"
invoiceNumber: "INV-001"
selectedOption: "A"
totalAmount: -100
zuoraStatus: "Posted"
ACTUALIZACIÓN ***** Para cualquiera que se encuentre con este problema, descubrí que la respuesta a continuación aborda el problema del mapa, pero después de la secuenciación, el mapa aún está alterado, así que terminé combinando esta solución pasando el objeto directamente: Cómo pasar un objeto desde un Asistente de componente Lightning para un método de controlador de Apex
var act = cmp.get("c.updateInvoices");
var tempInvoiceList = cmp.get('v.handleInvoices');
tempInvoiceList = tempInvoiceList.slice(); // copy
tempInvoiceList = tempInvoiceList.map(function(invoice) { return Object.assign({}, invoice); }); // copy deeper
act.setParams({ "invoices" : tempInvoiceList});
tempInvoiceList = tempInvoiceList
.forEach(function(invoice) {
invoice.availableOptions = invoice.availableOptions
.reduce(function(prev, option) {
prev[option.key] = option.value;
return prev;
},
{})
}
);
$A.enqueueAction(act);
Respuestas
@AuraEnabled global Map<String, String> availableOptions;
Debiera ser:
@AuraEnabled global List<Map<String,String>> availableOptions;
O:
@AuraEnabled global List<KeyValuePair> availableOptions;
Donde KeyValuePair
esta:
public class KeyValuePair {
@AuraEnabled public String key;
@AuraEnabled public String value;
}
Lo cual se usa con suficiente frecuencia en el código que realmente lo tengo como una clase de nivel superior en mi organización de desarrollo; Lo uso con bastante frecuencia para valores de listas de selección, etc.
Este tipo de JSON generalmente no se recomienda, pero si tiene que usarlo de esa manera, esta es la forma preferida. Para utilizar su Apex original, debe formatearse como:
"availableOptions": { "e": "f", "g", "z" },
Así es como JSON debe formatearse en el sentido general, aunque la forma anterior es aceptable para casos como opciones de lista de selección, que tienen un valor y una etiqueta.
Parece que necesita transformar sus "opciones disponibles" de nuevo en un mapa adecuado para utilizarlo correctamente:
var act = cmp.get("c.updateInvoices");
var tempInvoiceList = cmp.get('v.handleInvoices');
tempInvoiceList = tempInvoiceList.slice(); // copy
tempInvoiceList = tempInvoiceList.map(function(invoice) { return Object.assign({}, invoice); }); // copy deeper
tempInvoiceList = tempInvoiceList
.forEach(function(invoice) {
invoice.availableOptions = invoice.availableOptions
.reduce(function(prev, option) {
prev[option.key] = option.value;
return prev;
},
{})
}
);
var updatedInvoiceList = JSON.stringify(tempInvoiceLIst);
act.setParams({ "invoices" : updatedInvoiceList});
$A.enqueueAction(act);
availableOptions
en su JSON no es un mapa, es una lista de objetos (con campos "clave" y "valor").
Entonces, su clase contenedora debe reflejar eso. En lugar de a Map<String, String>
, debe convertirlo en una Lista de otra clase / tipo que pueda contener los datos de destino ("clave" y "valor")