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