ラッパークラスへのマップを使用してリストを逆シリアル化する方法

Aug 18 2020

ラッパークラス/オブジェクトに逆シリアル化しようとしている文字列があります。しかし、エラーが発生します:

Expected Map<String,String> but found [line:1, column:3]

ラッパークラス

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;

ライトニングコントローラー

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" />

ライトニングコントローラー

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"

UPDATE *****この問題にぶつかった人のために、以下の答えがマップの問題に対処していることを理解しましたが、文字列化した後もマップが変更されているため、オブジェクトを直接渡すこのソリューションの組み合わせを終了しました:からオブジェクトを渡す方法ApexControllerメソッドへのLightningコンポーネントヘルパー

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

回答

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

availableOptions JSONでは、マップではなく、オブジェクトのリストです(フィールド「key」と「value」を含む)。

したがって、ラッパークラスはそれを反映する必要があります。の代わりにMap<String, String>、ターゲットデータ(「キー」と「値」)を保持できる別のクラス/タイプのリストにする必要があります。