Tuesday, October 22, 2019

Deserializing Json Array in D365

I was experiencing an issue while creating a purchase requisition which has more than single line in D365  environment via service. The issue was actually specific to de-serializing the JSON array D365 (X++).  Here I am sharing with you the code which may be helpful for you.


   "purchaseRequisitionList":{ 
      "PurchaseRequisition":[ 
         { 
            "ItemId":"Item1",
            "ItemQty":3
  },
         { 
            "ItemId":"Item2",
            "ItemQty":2
         }
      ]
   }
}

First thing let's create data contracts similar to json above, where would define list for JSON  array.

[DataContract]
class PurchaseRequisitionList
{
    List purchaseRequistion;

    [DataMember("PurchaseRequisition")]

    public List parmLinesDetail(List _purchaseRequistion = purchaseRequistion)
    {
        purchaseRequistion = _purchaseRequistion;
        return purchaseRequistion;
    }

}


[DataContract]
class CreatePurchaseRequisitionContract

    ItemId                   itemId;
    Qty                      itemQty;


    [DataMember("ItemId")]

    public ItemId parmItemId(ItemId _itemId = itemId)
    {
        itemId = _itemId;
        return itemId;
    }

    [DataMember("ItemQty")]

    public Qty parmItemQty(Qty _itemQty = itemQty)
    {
        itemQty = _itemQty;
        return itemQty;
    }
}


It was the issue relating to de serializing of JSON array to our contract class. Add the following code to utilize the newtosoft for JObject.

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

Given below is the code for posting the purchase requisition. You can add exception handling and fields the way you like.

public EntityResponseContract PostPurchaseRequisitionNew(PurchaseRequisitionList purchaseRequisitionList)
{
  EntityResponseContract      response = new EntityResponseContract();
  str                         message;
  boolean                     success = false;
  PurchReqTable               purchReq;
  PurchReqLine                purchReqLine;


purchReq.clear();
purchReq.initValue();

purchReq.PurchReqId              = NumberSeq::newGetNum(PurchReqTable::numRefPurchReqId()).num();

purchReq.insert();

ListIterator linesDetailIterator = new ListIterator(purchaseRequisitionList.parmLinesDetail());


while(linesDetailIterator.more())

{
JObject headerJObject = linesDetailIterator.value();
purchaseRequisition = JsonParser::JsonToObject(classStr(CreatePurchaseRequisitionContract), headerJObject.ToString());

ttsbegin;

purchReqLine.clear();
purchReqLine.initValue();
purchReqLine.initFromPurchReqTable(purchReq);
purchReqLine.Name                   = purchaseRequisition.parmItemId();
purchReqLine.PurchQty               = purchaseRequisition.parmItemQty();
/*All your remaining fields you can place here*/
purchReqLine.insert();
ttscommit;

linesDetailIterator.next();

}
}

You can write a new class call it JsonParser, or simply type this method is class above.

public class JsonParser
{
//This method will deserialize the json to object
public static object JsontoObject(str _className,str _json)
    {
        Object      returnObject=null;
        try
        {
            returnObject= FormJsonSerializer::deserializeObject(className2Id(_className),_json);
        }
        catch
        {
            error("Unable to deserialize due to an error");
        }
        return returnObject;
    }
}

I hope that will also be a quick start for service end point.

2 comments:

  1. I have checked that out, and for json like following:

    {

    "success": true,

    "data": [

    {

    "CUST_GROUP_ID": 1,

    "CUST_GROUP_NAME": "Customer Group 1",

    "INSERT_FLAG": "Y",

    "RECORD_SENT_FLAG": "N",

    "ERROR_MESSAGE": null,

    "LAST_UPDATE_DATE": "2020-03-01T13:29:29.000Z",

    "LAST_UPDATED_BY": 0,

    "CREATION_DATE": "2020-03-01T13:29:29.000Z",

    "CREATED_BY": 0

    },

    {

    "CUST_GROUP_ID": 2,

    "CUST_GROUP_NAME": "Customer Group 2",

    "INSERT_FLAG": "Y",

    "RECORD_SENT_FLAG": "N",

    "ERROR_MESSAGE": null,

    "LAST_UPDATE_DATE": "2020-03-01T13:29:29.000Z",

    "LAST_UPDATED_BY": 0,

    "CREATION_DATE": "2020-03-01T13:29:29.000Z",

    "CREATED_BY": 0

    }

    ]

    }

    I am trying to create a job with below code

    .

    RetailWebRequest request;

    RetailWebResponse response;

    str rawResponse;

    RetailCommonWebAPI webApi;

    System.IO.Stream requestStream, responseStream;

    System.IO.StreamReader reader;

    Object deserializedContract;

    List list;

    ListIterator listIterator;

    CreateCustGroupContract custGroupContract;

    CustGroupList custGroupList;

    webApi = RetailCommonWebAPI::construct();

    request = RetailWebRequest::newUrl("URL");

    response = webApi.getResponse(request);

    rawResponse = response.parmData();

    custGroupList = new CustGroupList();

    listIterator = new ListIterator(custGroupList.parmDataDetail());

    while (listIterator.more())

    {

    custGroupContract = SMCFormJsonSerializer::deserializeObject(classIdGet(custGroupContract), listIterator.value());

    info(strFmt('%1', custGroupContract.parmCustGroupId()));

    info(custGroupContract.parmCustGroupName());

    listIterator.next();

    }

    but its only return "CUST_GROUP_ID": 1, "CUST_GROUP_NAME": "Customer Group 1".

    How can we achieve all the json string like "CUST_GROUP_ID": 1, "CUST_GROUP_NAME": "Customer Group 1", "CUST_GROUP_ID": 2, "CUST_GROUP_NAME": "Customer Group 2".

    Can you please help me to achieve the requirement.

    Thanks,

    Somesh

    ReplyDelete