54

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

4

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);
   }
}
40

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

  • 4
    There's an idea for this at: success.salesforce.com/ideaview?id=08730000000BrVaAAK – Bob Buzzard Aug 31 '12 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 '12 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. – Prafulla Patil Aug 31 '12 at 20:09
  • Good suggestion Bob on using interface based approach to achieve this requirement. – Abhinav Gupta Sep 3 '12 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 '12 at 18:15
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.

  • good point, I think this approach can work well for methods that return nothing i.e. VOID return type – Abhinav Gupta Sep 3 '12 at 8:53
9

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

  • 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? – Daniel Ballinger Apr 27 '16 at 1:54
  • @DanielBallinger I just updated answer to add this info – Prafulla Patil Feb 27 '17 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 '17 at 15:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.