Как десериализовать список с картой в wrapperclass
У меня есть строка, которую я пытаюсь десериализовать в класс-оболочку / объект. Но получаю ошибку:
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;
}
Строка
[
{
"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"
}
]
Апекс
system.debug((List<Invocable_Obj_HandleInvoice>) System.JSON.deserialize(invoices, List<Invocable_Obj_HandleInvoice>.class));
Список передан компоненту молнии
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;
Контроллер Lightning
var act = cmp.get("c.updateInvoices");
var updatedInvoiceList = JSON.stringify(cmp.get('v.handleInvoices'));
act.setParams({ "invoices" : updatedInvoiceList});
$A.enqueueAction(act);
Компонент <aura: attribute type = "List" name = "handleInvoices" />
Контроллер Lightning
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"
ОБНОВЛЕНИЕ ***** Для тех, кто сталкивается с этой проблемой, я понял, что ответ ниже решает проблему с картой, но после строкового преобразования карта все еще изменяется, поэтому я закончил комбинировать это решение, передавая объект напрямую: Как передать объект из Помощник компонента Lightning для метода контроллера 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);
Ответы
@AuraEnabled global Map<String, String> availableOptions;
Должно быть:
@AuraEnabled global List<Map<String,String>> availableOptions;
Или же:
@AuraEnabled global List<KeyValuePair> availableOptions;
Где KeyValuePair
находится:
public class KeyValuePair {
@AuraEnabled public String key;
@AuraEnabled public String value;
}
Который используется в коде достаточно часто, так что я действительно использую его как класс верхнего уровня в моей организации разработчиков; Я довольно часто использую его для значений раскрывающегося списка и так далее.
Такой тип JSON обычно не рекомендуется, но если вам нужно использовать его таким образом, это предпочтительная форма. Чтобы использовать исходный Apex, его необходимо отформатировать как:
"availableOptions": { "e": "f", "g", "z" },
Именно так JSON должен быть отформатирован в общем смысле, хотя предыдущая форма приемлема для таких случаев, как параметры раскрывающегося списка, которые имеют значение и метку.
Похоже, вам нужно преобразовать свой "availableOptions" обратно в правильную карту для правильного использования:
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
в вашем JSON - это не карта, это список объектов (с полями «ключ» и «значение»).
Итак, ваш класс-оболочка должен это отразить. Вместо a Map<String, String>
вам нужно сделать его List другого класса / типа, который может содержать целевые данные («ключ» и «значение»).