Close Mon Dec 10 18:37:10 GMT 2018

Sneaky dynamic method invocation Part 1

Picture the scene.

You're developing a managed package that exposes an Apex hook. Perhaps your initial approach includes:

  • a global interface and
  • an extension package that implements it

Unfortunately, the accompanying package dependency makes this approach an unnecessarily large hammer for some requirements.

Check this out:

Type reflector = Type.forName('NoDependencyHere');
String inputs = '{"arg1":true,"arg2":2}';
Object impl = Json.deserialize(inputs, reflector);
String output = String.valueOf(impl); //calls toString

What just happened from the caller's point of view?

  1. we referenced a piece of Apex code
  2. provided multiple input arguments
  3. invoked the code via Object.toString()
  4. received a return value that could be any type or types.

Because every object has a toString() method, this approach avoids:

  • a custom interface
  • hijacking a native interface like Process.Plugin
  • compiled dependencies on the invoked code.

Here's what the callee class looks like:

public class NoDependencyHere {
    
    Boolean arg1;
    Integer arg2;

    override public String toString() {
        //do work here
        List outputs = new List();
        
        //return outputs here
        return Json.serialize(outputs);
    }
    
}

Use case: shortcode parser in Apex

Consider  a Webpage__c custom object with a rich text area  Content__c custom field. Users wish to embed content within the rich text area using a Shortcode Parser (like Wordpress).

Video embedded using Apex shortcode parser:
[YouTube,v=c901NUazf3g,width=960,height=540/]

Using a regular expression, parse out the contents between the [brackets] - what's left is the implementation of current and future Shortcode parsers in the form of light-weight, self-contained Apex Classes.

public class YouTube {
    
    public String v; //see above
    public String width; //see above
    public String height; //see above
    
    override public String toString() {
        return ''
            + '<iframe width="'
            + this.width
            + '" height="'
            + this.height
            + '" src="//www.youtube.com/embed/'
            + this.v + '" frameborder="0" allowfullscreen>'
        ;
    }
}


Related