Wrapper Class in Salesforce

In this post, we will talk about the Wrapper class in Apex Salesforce. Wrapper Class is a class within a class that stores a group of similar or different data type variables into a single object.

What Is a Wrapper Class in Salesforce?

A wrapper class is a class, a data structure, or an abstract data type that contains different objects or collections of objects as its members. A wrapper class is a custom object defined by a programmer wherein he defines the wrapper class properties.

Example of Wrapper class

Here is an example of a Wrapper class in Salesforce.

public class AccountWrapperDemo {
  public Account acc {get; set;}
  public Contact cont {get; set;}
  public Boolean isSelected {get; set;}
}

What is the use of Wrapper Class in apex Salesforce

The use of Wrapper Class helps the developers in organizing the concerned data efficiently, provided the data is properly nested. Let see what is the use of wrapper class in Salesforce.

#1. Wrapper Class Use Cases in LWC

The structure of Wrapper Class is as efficient as that of a good data visualization technique for a web page, especially if the developers are dealing with the JSON structure using Lightning components.

  • Display the list of Open Cases in the Form of a data table.
  • Let the User have the ability to select multiple records a time.
  • Sending Wrapper object to Apex class.

1.1. Wrapper Class In Lightning Web Components

Take an example we need to show the Account record with its associated contact record on the LWC page.

AccountWrapperDemo Apex class

public with sharing class AccountWrapperDemo {
    @AuraEnabled(cacheable=true)
    public static List<AccountWrapper> getAccountWithContact(){
        List<AccountWrapper> wrapList = new List<AccountWrapper>();
        List<Account> accList = [ SELECT Id,Name,
                                        (SELECT Id,FirstName, LastName FROM Contacts)
                                    FROM Account LIMIT 5];
        if(!accList.isEmpty()){
            for(Account acc : accList){
                wrapList.add(new AccountWrapper(acc, acc.Contacts));
            }
        }
        return wrapList;
    } 
    public class AccountWrapper{
        @AuraEnabled public Account accRecord{get;set;}
        @AuraEnabled public List<Contact> contactList{get;set;}
        public AccountWrapper(Account accRecord, List<Contact> contactList){
            this.accRecord = accRecord;
            this.contactList = contactList;
        }
    }
}

lwcWrapperDemo

<template>
    <lightning-card title="Wrapper Class Demo in LWC" icon-name="custom:custom63">
    <template if:true={wrapperList.data}>
        <lightning-accordion class="example-accordion" >
            <template for:each={wrapperList.data} for:item="wrap">
                <lightning-accordion-section name={wrap.accRecord.Id} label={wrap.accRecord.Name} key={wrap.accRecord.Id}>
                    <template for:each={wrap.contactList} for:item="contWrap">
                        <lightning-layout vertical-align="center" key={contWrap.Id}>
                            <li>
                                {contWrap.FirstName}
                                {contWrap.LastName}
                            </li>
                        </lightning-layout>
                    </template>
                </lightning-accordion-section>

            </template>
        </lightning-accordion>
    </template>
</lightning-card>
</template>

Class Apex class in LWC.

import { LightningElement,wire } from 'lwc';
import getAccountWithContact from '@salesforce/apex/AccountWrapperDemo.getAccountWithContact';
export default class LWCWrapperDemo extends LightningElement {
    @wire(getAccountWithContact) wrapperList;
}

Result

Wrapper Class In Lightning Web Components
Wrapper Class In Lightning Web Components

#2. Salesforce Integration using Wrapper Classes: JSON to Apex

Using Wrapper classes in Integration is every normal use case. In Rest API we deal with the Request and response in JSON format. But it comes parsing the JSON response in Apex might be difficult to handle. But we can handle it easily with the help of converting the JSON into Apex.

The structure of Wrapper Class is as efficient as that of a good data visualization technique for a web page, especially if the developers are dealing with the JSON structure.

Take a example we have one JSON

{
  "invoiceList": [
    {
      "totalPrice": 5.5,
      "statementDate": "2023-10-04T16:58:54.858Z",
      "lineItems": [
        {
          "UnitPrice": 1,
          "Quantity": 5,
          "ProductName": "Apex"
        },
        {
          "UnitPrice": 0.5,
          "Quantity": 1,
          "ProductName": "Hours"
        }
      ],
      "invoiceNumber": 1
    },
    {
      "totalPrice": 11.5,
      "statementDate": "2023-10-04T16:58:54.858Z",
      "lineItems": [
        {
          "UnitPrice": 6,
          "Quantity": 1,
          "ProductName": "WrapperClass"
        }
      ],
      "invoiceNumber": 2
    }
  ]
}

We can convert the above JSON into Apex using the different tools available to convert JSON to Apex.


public class InvoiceWrapper{
	public cls_invoiceList[] invoiceList;
	class cls_invoiceList {
		public Double totalPrice;	//5.5
		public String statementDate;	//2023-10-04T16:58:54.858Z
		public cls_lineItems[] lineItems;
		public Integer invoiceNumber;	//1
	}
	class cls_lineItems {
		public Integer UnitPrice;	//1
		public Integer Quantity;	//5
		public String ProductName;	//Apex
	}
	public static InvoiceWrapper parse(String json){
		return (InvoiceWrapper) System.JSON.deserialize(json, InvoiceWrapper.class);
	}

	static testMethod void testParse() {
		String json=		'{"invoiceList":[{"totalPrice":5.5,"statementDate":"2023-10-04T16:58:54.858Z","lineItems":[{"UnitPrice":1,"Quantity":5,"ProductName":"Apex"},{"UnitPrice":0.5,"Quantity":1,"ProductName":"Hours"}],"invoiceNumber":1},{"totalPrice":11.5,"statementDate":"2023-10-04T16:58:54.858Z","lineItems":[{"UnitPrice":6,"Quantity":1,"ProductName":"WrapperClass"}],"invoiceNumber":2}]}';
		InvoiceWrapper obj = parse(json);
		System.assert(obj != null);
	}
}

2.1. Json.deserialize apex example

To parse JSON into an InvoiceWrapper instance, we can use the Serialization method in apex with JSON.serialize() and JSON.deserialize(). In our case, we can use the below code.

InvoiceWrapper ex = (InvoiceWrapper)JSON.deserialize(jsonString, InvoiceWrapper.class);

2.2. Json.serialize apex example

Alternately, to convert an InvoiceWrapper instance into JSON, execute below code

String jsonString = JSON.serialize(ex);

You can use the jsonString to pass in REST API as a body and use an ex instance to parse the response.

2.3. Parse a JSON String and Deserialize It into Objects

Here is sample code how you can use in REST API

HttpRequest request = new HttpRequest();
request.setEndpoint('API_URL');
request.setMethod('GET');

Http http = new Http();
HttpResponse response = http.send(request);
String responseBody = response.getBody();

InvoiceWrapper ex = (InvoiceWrapper)JSON.deserialize(responseBody, InvoiceWrapper.class);

System.debug('InvoiceWrapper Response ' + ex);

#3. Wrapper Class Use Cases on the Visual Force page

Display a table of records with a check box and then process only the records that are selected with the visualforce page.

public with sharing class WrapperDemoController {
   
    public List<AccountWrapper> listAccountWrapper {get; set;}
    public List<Account> selectedAccounts{get;set;}
    public WrapperDemoController (){
            listAccountWrapper = new List<AccountWrapper>();
            searchRecord();
    }
    public void searchRecord(){
        listAccountWrapper.clear();
            for(Account a: [select Id, Name,BillingState, Website, Phone ,Active__c from Account limit 10])
            {
                listAccountWrapper.add(new AccountWrapper(a));
            }
    }
    public void processSelected(){
        selectedAccounts = new List<Account>();
        selectedAccounts.clear();
        for(AccountWrapper wrapAccountObj : listAccountWrapper){
            if(wrapAccountObj.selected == true){
                selectedAccounts.add(wrapAccountObj.acc);
            }
        }
    }
    public void ActivateData(){
        for(Account acc : selectedAccounts ){
            acc.Active__c ='Yes';
        }
        update selectedAccounts ;
        searchRecord();
    }
    public void DeActivateData(){
        for(Account acc : selectedAccounts){
            acc.Active__c ='No';
        }
        update selectedAccounts ;
        searchRecord();
    }
    // This is our wrapper/container class.
    public class AccountWrapper {
        public Account acc {get; set;}
        public Boolean selected {get; set;}
        public AccountWrapper(Account a) {
            acc = a;
            selected = false;
        }
    }
}

VF Page

<apex:page controller="WrapperDemoController">
    <script type="text/javascript">
        function selectAllCheckboxes(obj, receivedInputID){
            var inputCheckBox = document.getElementsByTagName("input");
            for(var i=0; i<inputCheckBox.length; i++){
                if(inputCheckBox[i].id.indexOf(receivedInputID)!=-1){
                    inputCheckBox[i].checked = obj.checked;
                }
            }
        }
    </script>
    <apex:form >
        <apex:pageBlock id="PB1">
            <apex:pageBlockButtons >
                <apex:commandButton value="Add to Grid" action="{!processSelected}" rerender="table2,PB2"/>
            </apex:pageBlockButtons>
            <apex:pageblockSection title="All Accounts" collapsible="false" columns="1">
                <apex:pageBlockTable value="{!listAccountWrapper}" var="accWrap" id="table" title="All Accounts">
                    <apex:column >
                        <apex:facet name="header">
                            <apex:inputCheckbox onclick="selectAllCheckboxes(this,'inputId')"/>
                        </apex:facet>
                        <apex:inputCheckbox value="{!accWrap.selected}" id="inputId"/>
                    </apex:column>
                    <apex:column value="{!accWrap.acc.Name}" />
                    <apex:column value="{!accWrap.acc.BillingState}" />
                    <apex:column value="{!accWrap.acc.Phone}" />
                    <apex:column value="{!accWrap.acc.Active__c}" />
                </apex:pageBlockTable>
            </apex:pageblockSection>
        </apex:pageBlock>
        <apex:pageBlock id="PB2" >
            <apex:pageBlockButtons >
                <apex:commandButton value="Activate" action="{!ActivateData}" rerender="PB1,PB2"/>
                <apex:commandButton value="DeActivate" action="{!DeActivateData}" rerender="PB1,PB2"/>
            </apex:pageBlockButtons>
                <apex:pageBlockTable value="{!selectedAccounts}" var="c" id="table2" title="Selected Accounts">
                    <apex:column value="{!c.Name}" headerValue="Account Name"/>
                    <apex:column value="{!c.BillingState}" headerValue="Billing State"/>
                    <apex:column value="{!c.Phone}" headerValue="Phone"/>
                    <apex:column value="{!c.Active__c}" headerValue="Active"/>
                </apex:pageBlockTable>
        </apex:pageBlock>
    </apex:form>
</apex:page>
Wrapper Class Use Cases on the Visual Force page

Benefits Of Wrapper Class in Salesforce

  • We can store the data from multiple sObject using wrapper classes.
  • We can use a wrapper class in VF pagesLightning Component and we can also convert the JSON string into a wrapper class.
  • We can use Wrapper classes to parse the JSON request and response in REST API.

Summary

A wrapper or container class is a class, data structure, or abstract data type whose instances are collections of other objects. It is a custom object defined by a Salesforce developer where he defines the properties of the wrapper class. Within Apex & Visualforce this can be extremely helpful to achieve many business scenarios within the Salesforce CRM software.

Amit Chaudhary
Amit Chaudhary

Amit Chaudhary is Salesforce Application & System Architect and working on Salesforce Platform since 2010. He is Salesforce MVP since 2017 and have 17 Salesforce Certificates.

He is a active blogger and founder of Apex Hours.

Articles: 473

3 Comments

  1. Such a class has no clear purpose. “The use of Wrapper Class helps the developers in organizing the concerned data efficiently, provided the data is properly nested.” – It just indicates a poorly thought-off object oriented abstraction. Such classes should be strictly avoided.
    Please read about SOLID design principles for better object oriented design https://en.wikipedia.org/wiki/SOLID

    • Thanks for your feedback Vibhor. But you can let me know the issue in above code and why you are able to see clear purpose in code.

      Example 1) public class AccountWrapper
      Contain code which is following proper abstraction to bind the account and contact data. Properly is public because we need to bind it to LWC.

      Sample 2) Is also good example of JSON to Apex.

      • I agree Amit, I’m not sure Vibhor has much salesforce experience! Thanks for the post, comprehensive and easy to understand. I’ve made a website that I think improves on the original json2apex converter in a few different ways (immediate results, more error handling, explanation of how to use it). Let me know what you think.

Leave a Reply

Your email address will not be published. Required fields are marked *