Find your content:

Search form

You are here

Dynamic execution of classes in Apex

 
Share

How can I dynamically execute classes in Apex? What if I don't know at compile time which class should be instantiated? Rather, I would like to decide at runtime which class would be appropriate to instantiate based on a variety of conditions.


Attribution to: Adam

Possible Suggestion/Solution #1

Here is a bare-bones example of leveraging the Class Factory design pattern in Apex. It's an interface-based approach that permits dynamic class instantiation. The only requirement is to implement the interface method(s) but the rest of the class internals participating in the class factory can be completely unique (Class1, Class2, etc.)

ClassFactory:

public with sharing class ClassFactory 
{
    // Class Factory template
    public interface IClassFactory
    {
        void processWork();
    }

    // Class Factory base class
    public virtual class ClassFactoryBase
    {
        // ... Shared methods go here
    }


    // Process work 
    public static void processAllWork()
    {
        ClassFactoryManager cfm = new ClassFactoryManager();
        cfm.newClassInstance('ClassFactory.Class1').processWork();
        cfm.newClassInstance('ClassFactory.Class2').processWork();
        cfm.newClassInstance('ClassFactory.Class3').processWork();
        cfm.newClassInstance('ClassFactory.Class4').processWork();
    }

    // Class1
    public class Class1 extends ClassFactoryBase implements IClassFactory
    {
        public void processWork()
        {
            // ... Class-specific work goes here
        }
    }

    // Class2
    public class Class2 extends ClassFactoryBase implements IClassFactory
    {
        public void processWork()
        {
            // ... Class-specific work goes here
        }
    }

    // Class3
    public class Class3 extends ClassFactoryBase implements IClassFactory
    {
        public void processWork()
        {
            // ... Class-specific work goes here
        }
    }

    // Class4
    public class Class4 extends ClassFactoryBase implements IClassFactory
    {
        public void processWork()
        {
            // ... Class-specific work goes here
        }
    }
}

ClassFactoryManager: (modified - thanks for the suggestion Peter)

public with sharing class ClassFactoryManager 
{
    public ClassFactoryManager(){}

    // Return the appropriate class instance based on className
    public ClassFactory.IClassFactory newClassInstance(String className)
    {
        Type t = Type.forName(className);
        return (ClassFactory.IClassFactory) t.newInstance();
    }
}

Ahhhh.... much better.


Attribution to: Adam

Possible Suggestion/Solution #2

With the Callable interface that was introduced in Winter '19 you can now build a light weight interface for the methods you want to dynamically call from a class. Combining that with the Type class you have the option to instantiate the class dynamically and call any methods you expose in the call() method of the class dynamically.

The example below is from the callable interface docs which highlights both dynamic instantiation of classes and calling of methods.

Example class you want to dynamically call

public class Extension implements Callable {

   // Actual method
   String concatStrings(String stringValue) {
     return stringValue + stringValue;
   }

   // Actual method
   Decimal multiplyNumbers(Decimal decimalValue) {
     return decimalValue * decimalValue;
   }

   // Dispatch actual methods
   public Object call(String action, Map<String, Object> args) {
     switch on action {
       when 'concatStrings' {
         return this.concatStrings((String)args.get('stringValue'));
       }
       when 'multiplyNumbers' {
         return this.multiplyNumbers((Decimal)args.get('decimalValue'));
       }
       when else {
        throw new ExtensionMalformedCallException('Method not implemented');
       }
     }
   }

   public class ExtensionMalformedCallException extends Exception {}
}

Unit test demonstrating the dynamic calling

@IsTest
private with sharing class ExtensionCaller {

   @IsTest
   private static void givenConfiguredExtensionWhenCalledThenValidResult() {

      // Given
      String className = 'Extension'; // Variable to demonstrate setting class name
      String methodName = 'multiplyNumbers'; // Variable to demonstrate setting method name
      Decimal decimalTestValue = 10;

      // When
      Callable extension = (Callable) Type.forName(className).newInstance();
      Decimal result = (Decimal) extension.call(methodName, new Map<String, Object> { 'decimalValue' => decimalTestValue });

      // Then
      System.assertEquals(100, result);
   }
}

Attribution to: Clint

Possible Suggestion/Solution #3

Now this is possible in apex using Tooling API.

> ToolingAPI x = new ToolingAPI(); ToolingAPI.ExecuteAnonymousResult
> toolingResult = x.executeAnonymousUnencoded("Your apex code as a
> string here");

Please refer blog post - http://codefriar.wordpress.com/2014/10/30/eval-in-apex-secure-dynamic-code-evaluation-on-the-salesforce1-platform/


Attribution to: Prafulla Patil
This content is remixed from stackoverflow or stackexchange. Please visit https://salesforce.stackexchange.com/questions/1116

My Block Status

My Block Content