New Apex Type Methods in Summer ’12

The Summer '12 release of Salesforce.com has already started rolling out to sandbox orgs, and is scheduled to roll out to production orgs in June. In this post, learn about the new 'getName' and 'newInstance' methods to the Apex Type system class.

The recent fog in San Francisco can only mean one thing. It’s summer time! Specifically, it’s Summer ’12 release time. The next release of Salesforce.com has already started rolling out to Sandbox Orgs, and is scheduled to roll out to Production Orgs in June. To get a sneak peek at some of the exciting new Developer features in the Summer ’12 release, you can register for the preview webinar that Pat and I are hosting on Wednesday (5/16).

Today, I want to highlight an important new addition to Apex that is easy to miss when perusing the Summer ’12 release notes – the addition of ‘getName’ and ‘newInstance’ methods to the Type system class. These new methods now allow you to instantiate Apex classes at runtime with just the String name of the class. No longer do you have to specify the type of class you want instantiated at compile time (e.g. MyClass newObj = new MyClass();). You can instead do something like this:

Type t = Type.forName('MyClass');
MyClass newObj = (MyClass)t.newInstance();

Experienced Java developers will recognize this as the start of supporting Reflection in the Force.com platform. Though Apex does not fully support all the features typically associated with Reflection yet, the ‘Type.newInstance’ method is an important step in that direction. Lets take a specific use case and walk through the how and why of this new Apex feature.

Imagine that you’re an ISV partner that has created a Managed Package on the Force.com platform (for listing on the AppExchange) to validate US Zip Codes for all Contact records added or updated in a Salesforce Org. Let say that your default implementation of this zip code validation checks for a valid 10 character zip code (e.g. ‘94105-1234’). Some of your package subscribers might however wish to customize the validation logic by for example checking for a 5 digit zip instead. Since subscribers are prevented from viewing the code included in a Managed Package (for protecting the ISV’s IP), its not simply a matter of modifying the Apex logic included in the package. The new Type methods offer an elegant solution by allowing subscribers to author their own zip code validation and then having your package dynamically detect and instantiate that ‘override’ at runtime. Lets walk through the package design.

The first piece of the puzzle is to define a simple interface that all zip code validation scripts need to implement.

global interface ValidateZipCode {

    boolean isValidUSZip(String zip);

}

Next, lets say that your package includes a ‘default’ implementation that checks for a 10 character zip code.

global class ValidateZipCodeDefaultImpl implements ValidateZipCode {
    ...
    global boolean isValidUSZip(String zip){
        //Check for a valid 10 character zip code
        //and return true or false as appropriate
    }
}

Now say that one of your package subscribers wishes to implement a different validation logic. All they have to do, is to author a different implementation class. Something like

global class ValidateZipCodeMyCustomImpl implements ValidateZipCode {
    ...
    global boolean isValidUSZip(String zip){
        //Check for a valid 5 digit zip code and return true or false as appropriate
    }
}

Now comes the fun part. In order to pick the appropriate zip code validator, I’ve implemented the classic Factory design pattern.

global class ZipCodeValidatorFactory {
    public static ValidateZipCode getValidatorInstance(){
        String defaultZipCodeValidationClass =
               ValidateZipCodeDefaultImpl.class.getName();
        String zipCodeValidationClass;

        Zip_Code_Custom_Impl__c settings =
               Zip_Code_Custom_Impl__c.getInstance('Zip Code Validation');

        if (settings != null && settings.Zip_Code_Validation_Class__c != null) {
            zipCodeValidationClass = settings.Zip_Code_Validation_Class__c;
        }
        else {
            zipCodeValidationClass = defaultZipCodeValidationClass;
        }

        Type t = Type.forName(zipCodeValidationClass);
        ValidateZipCode zipCodeValidator = (ValidateZipCode)t.newInstance();
        return zipCodeValidator;
    }
}

By default, this factory class returns the default zip code validator class (ValidateZipCodeDefaultImpl) included in my Managed Package. However, subscribers can specify an ‘override’ by populating a Custom Setting (Zip_Code_Custom_Impl__c) with the name of the Apex class that implements the ValidateZipCode interface per their specific requirements. In the example above, the subscriber would set this Custom Setting to ‘ValidateZipCodeMyCustomImpl’. In my Factory class above, I can dynamically instantiate the correct zip code validator by using the ‘newInstance’ method (line 18).

The final piece of the puzzle is how I use the above Factory class to validate Contact zip codes. Here is the trigger code for that.

trigger CheckZipCodeTrigger on Contact (before insert, before update) {

    ValidateZipCode zipCodeValidator = ZipCodeValidatorFactory.getValidatorInstance();

    for (Contact c: Trigger.new)
    {
        if (c.MailingPostalCode != null && !zipCodeValidator.isValidUSZip(c.MailingPostalCode))
        {
            c.addError('Invalid Zip Code');
        }
    }
}

Hopefully the example above has helped illustrate the power of the new Type methods in Summer ’12. If you have another interesting use case for ‘Type.newInstance’, please comment on the post and share it with the community.

Leave your comments...

New Apex Type Methods in Summer ’12