64

Is there any way I can call apex method from class if both class name and method are stored in the string.

String strClass = 'BatchUtil';
String strMethod = 'updateAccounts'

now I want to call above method.. is it possible ?

I was doing research and came across following - (not sure how this works and how to call it from salesforce)

ExecuteAnonymousResult[] = binding.executeanonymous(string apexcode);

http://www.salesforce.com/us/developer/docs/apexcode/Content/sforce_api_calls_executeanonymous.htm

1

4 Answers 4

22

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.

The example below is from the docs (tweaked to show dynamic method naming):

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);
   }
}
2
  • Thank you Client for pointing out Callable interface. I have expanded beyond Salesforce documentation for end-to-end automation: salesforce.stackexchange.com/questions/297847/… Your thoughts / feedback? Mar 12, 2020 at 20:46
  • I have actually been struggling to decide when this is actually useful. If I'm going to give someone a list of actions and arguments, I might as well give them an interface. I have been trying to come up with a clever way to use this to resolve the dependencies issues. e.g. I have a core package, I made the mistake of putting in common interfaces. How do I move it into the correct package, without breaking dependencies...
    – Bill
    Sep 5, 2020 at 14:29
45

While you can instantiate a class based on its name using the Type system class, you can't dynamically locate a method and execute it. The best that you can do is to dynamically create an instance of a class that implements an interface and execute one of the methods on the interface.

There's more information on the Type class and an example in the :

Apex Developer's Guide

8
  • 4
    There's an idea for this at: success.salesforce.com/ideaview?id=08730000000BrVaAAK Aug 31, 2012 at 7:28
  • 1
    From the instance method, you could, of course, just call the static method you originally wanted to call.
    – metadaddy
    Aug 31, 2012 at 16:42
  • this is awesome never thought about this approch.. thanks a lot Bob and Metadaddy... and thanks a ton to stackexchange as well. I am going to implement this approach now and will post my code so that others can benefit from it. Aug 31, 2012 at 20:09
  • Good suggestion Bob on using interface based approach to achieve this requirement. Sep 3, 2012 at 8:50
  • 1
    This is a good related read: en.wikipedia.org/wiki/Factory_method_pattern. I'm going to post one of my Apex class factory implementations as a question/answer.
    – Adam
    Sep 3, 2012 at 18:15
12

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/

ToolingAPI class is taken from here - https://github.com/afawcett/apex-toolingapi/blob/apex-toolingapi-rest/src/classes/ToolingAPI.cls

3
  • 2
    There is the executeAnonymousUnencoded method coming from? The Tooling API has an executeAnonymous operation in the WSDL. Is the Unencoded part something from how you implemented it in Apex? Apr 27, 2016 at 1:54
  • @DanielBallinger I just updated answer to add this info Feb 27, 2017 at 17:55
  • Is there a synchronous way to execute a method so that I can read the response and act on it in my bigger/larger process?
    – VarunC
    Jun 12, 2017 at 15:06
10

Update

Based on Kevin's post about adding EVAL() in Apex I created a variation that parses the response out of the Debug log. This uses the Apex API rather than the Tooling API. See Adding Eval() support to Apex.

With this you can do things like:

string output = soapSforceCom200608Apex.evalString('string first = \'foo\'; string second = \'bar\'; string result = first + second; System.debug(LoggingLevel.Error, result);');  
System.assertEquals('foobar', output);  
System.debug(output); 

The answer to How to use/invoke "execute Anonymous" calls from Apex/Controller is:

You can't invoke executeAnonymous from another block of Apex. Execute anonymous is a separate entry point to compile & run a routine which can only be invoked through the API verb - see the apex WSDL: /services/wsdl/apex

So you could in theory import the Apex WSDL back into Salesforce, which would give you binding from your example. Then you just need to build up a string with the Apex code that you would pass into the execute anonymous method. See update above for sample implementation.

You could use the article Calling Salesforce Web Services Using Apex as an example, substituting the apex WSDL for the partner API WSDL.

1
  • good point, I think this approach can work well for methods that return nothing i.e. VOID return type Sep 3, 2012 at 8:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .