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.

tagged , , , Bookmark the permalink. Trackbacks are closed, but you can post a comment.
  • http://twitter.com/TehNrd Jason Venable

    Nice simple example that shows how this new feature can be utilized. Thanks!

  • http://sbwdev.myopenid.com/ Sebastian Wagner

    no exactly the same use case as above but you might want to check out Email2Apex. I created it to chain Batch jobs, but in general it can instantiate apex classes incl. parameters. ., still on API 23 but I’m going to update it soon.

    https://github.com/sbwdev/Email2Apex

  • Abhinav Gupta

    Good post Sandeep, it reminds me all of those classic Java days :)

  • http://twitter.com/rbklaassen Ronald Klaassen

    Just tried to use the Type system class, but it doesn’t help me out.
    I’m trying to dynamically schedule a class like this:
    String className = ‘MySchedulableClass’;
    Type t = Type.forName(this.className);
    System.schedule(‘myJobName’, ‘myCronString’, t.newInstance());

    The schedule method doesn’t like this and my class will not save. Only when I cast the result to MySchedulableClass the class saves. But then my class isn’t dynamic anymore and I need to modify my class each time I add a schedulable class.

    As I look at your example, I see the same. Surely you dynamically instantiate your class, but you still need to cast it. Can you tell me the advantage over just instantiating the class like:
    MySchedulableClass cls = new MySchedulableClass();

    Kind regards!

    • http://twitter.com/kevino80 Kevin O’Hara

      Meant to reply to you directly but the answer to this is in my above comment.

    • http://twitter.com/_drako Richard Tuttle

      Ronald, you’re not casting it as anything other than Type. Do you have a superclass or interface that you can cast it as? In the example he cast it as the interface “ValidateZipCode”. If you have a reason to dynamically schedule more than one job that is similar then you could create an interface that describes them both with a common interface.

  • http://twitter.com/kevino80 Kevin O’Hara

    Ronald, you would want to cast your t.newInstance() to the Schedulable interface

    System.schedule(‘myJobName’, ‘myCronString’, (Schedulable) t.newInstance());

    • http://twitter.com/rbklaassen Ronald Klaassen

      Yeah, that did the trick! Thanks!

  • http://twitter.com/_drako Richard Tuttle

    Kevin actually made a better point, since it’s scheduled you can just cast to the interface used for schedulable classes. Completely forgot they use that interface already :)

  • http://twitter.com/chrisodavies Chris O Davies

    Great post! nice to see Reflection finds a place in #apex.

  • http://twitter.com/almazanjl José Luis Almazán

    Very interesting!

  • http://twitter.com/Force2be Michael Smith

    Really nice feature. Effectively adds “black box plug-in” functionality to apps. I wonder if this would work with add-on’s to a managed package, such as a separately purchased option.

  • http://twitter.com/FishOfPrey Daniel Ballinger

    Note that there is a known issue related to this that can prevent a managed package from finding the subscribing Orgs local class.

    Type.forName(String) in managed package does not resolve local apex
    class – https://sites.secure.force.com/success/issues_view?id=a1p30000000SVY3AAO

    • Anonymous

      Daniel – that is indeed a known issue, and the link you posted also contains a workaround for those affected by this. Thanks for posting.

  • Jason Venable

    With regards to managed packages and implementing the interface on to a subscriber defined class, does this need to reference the namespace of the interface?

  • Antoine Magnier

    Hi,

    thanks for this great idea/article.

    I used it in one of my SF ISV / managed package project. Maybe you can add one detail : If the factory needs to load a custom instance implementing the interface you need to use Type.forName with two arguments : first argument is namespace so put an empty string & the second one is the name of the implemenation class.

    If you use only one argument the factory will not succeed in loading the custom class in one subscriber org.

    Regards

    Antoine from France