JSON Deserialization in Salesforce

JSON Logo

I have been several posts recently on the Developer Boards around JSON deserialization and some weird and convoluted ways to convert it into something that is useful for Salesforce.  Let’s talk about what I have found is the cleanest way to handle JSON deserialization.

JSON Payload

Let’s take a look at our JSON payload.  I am taking the payload from the docsample Heroku app since it’s an easy way to get consistent data from a webservice.

{
  "invoiceList": [
    {
      "totalPrice": 5.5,
      "statementDate": "2011-10-04T16:58:54.858Z",
      "lineItems": [
        {
          "UnitPrice": 1,
          "Quantity": 5,
          "ProductName": "Pencil"
        },
        {
          "UnitPrice": 0.5,
          "Quantity": 1,
          "ProductName": "Eraser"
        }
      ],
      "invoiceNumber": 1
    },
    {
      "totalPrice": 11.5,
      "statementDate": "2011-10-04T16:58:54.858Z",
      "lineItems": [
        {
          "UnitPrice": 6,
          "Quantity": 1,
          "ProductName": "Notebook"
        },
        {
          "UnitPrice": 2.5,
          "Quantity": 1,
          "ProductName": "Ruler"
        },
        {
          "UnitPrice": 1.5,
          "Quantity": 2,
          "ProductName": "Pen"
        }
      ],
      "invoiceNumber": 2
    }
  ]
}

So we can see here that the data provided is an invoice list and each invoice contains data and line items for that invoice.

JSON Deserialization

Data Structure

Now we need to create a data structure to hold our the JSON we deserialize

public class InvoiceWrapper {
    public class LineItem {
        public Double unitPrice {get; set;}
        public Double quantity {get; set;}
        public String productName {get; set;}

        public Double getLineItemTotal() {
            return this.unitPrice * this.quantity;
        }
    }

    public class Invoice {
        public Double totalPrice {get; set;}
        public DateTime statementDate {get; set;}
        public String contactnumber {get; set;}
        public List<LineItem> lineItems {get; set;}
        public Integer invoiceNumber {get; set;}
    }

    public List<Invoice> invoiceList {get; set;}
}

This wrapper class now contains our two sub-classes (LineItem and Invoice) as well as our variable for our invoice list.  The nice thing about doing it as a class is we can add helper methods to also manipulate data.  There is a getLineItemTotal method that we can use in our display.

Data Parsing

Now we need to pull the data from the endpoint and using JSON deserialization push it into our data structure.

public class JSONDeserialize {
    public InvoiceWrapper wrapper {
        get;
        set;
    }

    public void deserialize() {
        Http h = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndPoint('https://docsample.herokuapp.com/jsonSample');
        request.setHeader('Content-type', 'application/json');
        request.setMethod('GET');

        HttpResponse response = h.send(request);

        wrapper = (InvoiceWrapper) JSON.deserializeStrict(response.getBody(), InvoiceWrapper.class);
    }
}

If your JSON data is going to change (or could change) you can use deserialize instead of deserializeStrict to make it not explode when the JSON deserialization happens.

Data Display

Now that we have a way to get the data in a meaningful structure, let’s display it on a Visualforce page

<apex:page controller="JSONDeserialize">
    <apex:form >
        <apex:pageBlock title="JSON Deserialize Response">
            <apex:pageBlockButtons >
                <apex:commandButton value="submit" action="{!deserialize}" reRender="invoiceBlock"/>
            </apex:pageBlockButtons>
            <apex:pageBlockSection id="invoiceBlock" columns="1">
                <apex:repeat value="{!wrapper.invoiceList}" var="invoice">
                    <apex:pageBlockSection columns="2">
                        <apex:facet name="header">Invoice {!invoice.invoiceNumber}</apex:facet>
                        <apex:pageBlockSectionItem >
                            <apex:outputLabel value="Total Price" for="totalPrice" />
                            <apex:outputText value="{!invoice.totalPrice}" id="totalPrice" />
                        </apex:pageBlockSectionItem>
                        <apex:pageBlockSectionItem >
                            <apex:outputLabel value="Statement Date" for="statementDate" />
                            <apex:outputText value="{!invoice.statementDate}" id="statementDate" />
                        </apex:pageBlockSectionItem>
                    </apex:pageBlockSection>
                    <apex:pageBlockSection columns="1">
                        <apex:facet name="header">Invoice {!invoice.invoiceNumber} Items</apex:facet>
                        <apex:pageBlockTable value="{!invoice.lineItems}" var="item" id="lineItems">
                            <apex:column value="{!item.productName}" headerValue="Product Name" />
                            <apex:column value="{!item.quantity}" headerValue="Quantity" />
                            <apex:column value="{!item.unitPrice}" headerValue="Unit Price" />
                            <apex:column value="{!item.lineItemTotal}" headerValue="Total" />
                        </apex:pageBlockTable>
                    </apex:pageBlockSection>
                </apex:repeat>
            </apex:pageBlockSection>
        </apex:pageBlock> 
    </apex:form>
</apex:page>

Now when we click the submit button we can see the data coming in and when it’s pressed we deserialize the data and reRender the section

JSON Deserialization in action

This entry was posted in Development, Salesforce and tagged , , . Bookmark the permalink.
  • JimBTek

    This article makes it really straightforward to see how to do this step by step. Would be interesting to have a second piece that includes storing the data in a Salesforce custom object, and perhaps even different ways of getting this data to sync 1-way or 2-ways. Thanks for the great article!

  • You mean extending this so that the data in InvoiceWrapper is stored into an Invoice__c object? Can you expand upon what you mean by “1-way or 2-ways” sync?

  • JimBTek

    Yeah storing the data in a custom object.

    1-way: Sync data from JSON to Salesforce ongoing (think syncing in invoices for read only purpose in Salesforce

    2-way: User edits the Invoice record in Salesforce and it pushes back through JSON to Heroku, etc.

    Currently on a project that does 2-way syncing of invoices between Salesforce and Quickbooks Online, but we use a 3rd party syncing tool that uses XML to map across the two. It would be interesting to see more of how to roll your own connection.

  • Jerry Clifft

    I would really like to see this write the data to a custom object/fields instead of displaying to visualforce.

  • I’ll try to write something up for you, but there are two ways to do this. You can do the object way above and add a method that converts the data to an sObject or if the incoming JSON is in the same format as your sObject you can just deserialize it directly using sObject.class

  • Hi, I just tried to use your method in my org but struggling to get the results.

    https://developer.salesforce.com/forums/ForumsMain?id=9060G000000UZKvQAO

  • I’ve replied back to your post