Comment désérialiser une liste avec une carte en classe wrapper

Aug 18 2020

J'ai une chaîne que j'essaie de désérialiser en une classe / objet wrapper. Mais obtenez l'erreur:

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;
}

Chaîne

[
  {
    "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"
  }
]

Sommet

 system.debug((List<Invocable_Obj_HandleInvoice>) System.JSON.deserialize(invoices, List<Invocable_Obj_HandleInvoice>.class));  

Liste passée au composant Lightning

 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;

Contrôleur Lightning

var act = cmp.get("c.updateInvoices");
var updatedInvoiceList = JSON.stringify(cmp.get('v.handleInvoices'));
act.setParams({ "invoices" : updatedInvoiceList});
$A.enqueueAction(act); 

Composant <aura: attribute type = "List" name = "handleInvoices" />

Contrôleur 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"

MISE À JOUR ***** Pour quiconque se heurte à ce problème, j'ai compris que la réponse ci-dessous traite du problème de la carte, mais après avoir stringifié la carte est toujours modifiée, j'ai donc fini de combiner cette solution en passant l'objet directement: Comment passer un objet à partir d'un Assistant de composant Lightning pour une méthode de contrôleur 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); 

Réponses

3 sfdcfox Aug 18 2020 at 19:40
@AuraEnabled global Map<String, String> availableOptions;

Devrait être:

@AuraEnabled global List<Map<String,String>> availableOptions;

Ou:

@AuraEnabled global List<KeyValuePair> availableOptions;

KeyValuePairest:

public class KeyValuePair {
  @AuraEnabled public String key;
  @AuraEnabled public String value;
}

Ce qui est assez couramment utilisé dans le code pour que je l'utilise en tant que classe de premier niveau dans mon organisation de développement; Je l'utilise assez fréquemment pour les valeurs de liste de sélection et ainsi de suite.

Ce type de JSON est généralement déconseillé, mais si vous devez l'utiliser de cette façon, c'est la forme préférée. Afin d'utiliser votre Apex d'origine, il doit être formaté comme suit:

"availableOptions": { "e": "f", "g", "z" },

C'est ainsi que JSON est censé être formaté au sens général, bien que le formulaire précédent soit acceptable pour des cas tels que les options de liste de sélection, qui ont une valeur et une étiquette.


Il semble que vous deviez transformer vos "options disponibles" en une carte appropriée pour être utilisée correctement:

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); 
DerekF Aug 18 2020 at 19:41

availableOptions dans votre JSON n'est pas une carte, c'est une liste d'objets (avec les champs "clé" et "valeur").

Votre classe wrapper doit donc refléter cela. Au lieu d'un Map<String, String>, vous devez en faire une liste d'une autre classe / type pouvant contenir les données cibles ("clé" et "valeur")