[SalesForce] Purpose of an inner class

I've read in the Apex Workbook and the Apex Developer Guide the mention of inner classes. What is their purpose?

I see in the Apex Workbook that they used private variables and setter/getter methods in the inner class, but why didn't they just do that in the outer class with a constructer, getter, and setter?

Best Answer

I think this question is way too broad for one answer to cover. I suggest you look at some libraries out there to see how they use inner classes.

There are so many use cases. It would be really difficult to cover them all. But I will just cover three here:

  • Generalization (DRY)
  • Selection Wrappers
  • Deserialization

Generalization (DRY)

I know for my DML library, I use a few, all of which have their behavior defined by interfaces. But that is neither here nor there.

Maybe a concrete example will help you better understand. Take a look at the GenericResult inner class in my DMLResults class.

public class GenericResult
{
    final Id recordId;
    final List<Database.Error> errors;
    public GenericResult(Id recordId, List<Database.Error> errors)
    {
        this.recordId = recordId;
        this.errors = (errors != null) ? errors : new List<Database.Error>();
    }
    public Id getId() { return recordId; }
    public List<Database.Error> getErrors() { return errors; }
}

This class helps me out with DRY programming by letting me use one class to represent all of the *Result system classes (see also: Do the *Result objects in Database have a common ancestor?). Because of this implementation, my PartialResult logic can use GenericResult instances once instead of repeating the logic once each for SaveResult, UpsertResult, DeleteResult, etc.


Selection Wrappers

Often wrapper classes are often used for record selection on a Visualforce Page. This can be as simple as:

public class MyObjectWrapper
{
    public Boolean isSelected { get; set; }
    public MyObject__c record { get; private set; }
    public MyObjectWrapper(MyObject__c record)
    {
        this.record = record;
        this.isSelected = false;
    }
}

Then in your markup, you would see something like:

<apex:repeat value="{!wrappers}" var="wrapper">
    <apex:inputCheckbox value="{!wrapper.isSelected}">
    <!--other output-->
</apex:repeat>

Deserialization

Deserialization is much simpler using an inner class, though you can use top-level classes as well.

public class TopLevel
{
    public class SomeStructure
    {
        public String someProperty;
    }
}

Then you can deserialize using this class like:

SomeStructure data = JSON.deserialize(
    '{"someProperty": "<value>"}',
    TopLevel.SomeStructure.class
);
Related Topic