Reflection support in Force.com Apex

Addressing a common problem usually solved by following well known behavioural design patterns like the strategy pattern, as an example for how reflection capabilities can significantly increase the quality of an applications source code.

The Force.com Summer ´12 release already introduced enhanced reflection capabilities to the APEX language (for more details: http://developer.force.com/releases/release/summer12).

Compared to mature reflection APIs other languages provide, the very few static and instance methods bound to the System.Type class seem to be not very powerful, but the newly implemented forName() and getInstance() methods are the key to a lot more reusable, decoupled, thus readable ind reasonable code.

This article will address a common problem usually solved by following well known behavioural design patterns like the strategy pattern, as an example for how reflection capabilities can significantly increase the quality of an applications source code.

Consider requirement to implement an extensible VisualForce component that always has to perform similar tasks, but relies on a very varying data model, e.g. different field names of the underlying Sobject fields, different sobject relationships and so on.

A key feature is that the newly introduced component has to be easily portable for quickly supporting newly introduced data structures like sobjects, but any other datasource should be supported, too. The requirement is that is must be possible to only place the component on any visualforce page, pass a list of arbitrary arguments and decide — dependent on the characteristics of the given arguments — which supported process has to be dispatched.

To achieve this goal, we first need a factory which can create process instances on-the-fly, based on the arguments passed to the visualforce component.

With legacy APEX code, this has only been possible by creating an IF/ELSE- „conditional tree“, placed directly in your factory class. A code sample could read like:

As you can see, deciding between and creating only three different processes produces a lot of more or less hard-to-read code. Ok, these few lines are rather reasonable, but imagine, what if you have to support 10, 20 or more different process classes? It is not difficult to forsee that you will probably produce a nightmare of god-object that knows everything about which process supports which source model.

So we face several problems here:

  • Lots of always-the-same boilerplate code. Extensibility feature #1: Copy ’n
    paste.
  • Maintenance problem: For instance, changing the priority of two similar
    processes (processes working e.g. on the same data model), or adding new
    processes, will most likely result in heavy code changes.
  • Only the factory, our „god object“, knows which model is supported by which
    process. This is a SOC-fault: The processes themself should hold the
    information on how and when to match a given input model.
  • Unit testing is hard to archive due to the „big ball of mud“ produced in the
    factory class. Changes to the factory may implicitely require to change
    the unit tests, too.

Now let´s take a look on how the newly introduced reflection method may support you to restructure the code in a better way. At first, i will shortly describe the processes interface:

The interface definition is straightforward. It extends the (also new with Summer ’12) Force.com´s own Comparable interface which requires classes that implement MyProcessInterface to implement a compareTo(Object compareTo) method, too.

Our interface required at least three method to be existant in each implementation:

ProcessDispatchResult process() defines how to process the given model, it is the „daily business“ of each process implementation.

Boolean supports(Object model, Mapparameters) This method can be called to determine if the current process implementation really „supports“ the given object model and parameters. It is the direct replacement for these large if/else-constructs that is currently yet placed in our factory class. Consider this method to be the solution to our „got-object“- problem.

Void setPriority(Integer priority), Integer getPriority() This method can be used to give (or access from) a process a priority compared to other processes. Guess this has something to do with the Comparable interface? You are probably right.

Now let´s see how a sample implementation for a process could look like:

All required methods has been implemented. Taking a closer look, we see a very uninteresting process() method that actually does nothing. Rather more interesting for us the support() method. It returns true if the given model is an Account instance, otherwise false. The priority you meight set by calling setPriority() is evalutated within compareTo: Each process is compared by it´s „priority“. So processes with lesser priority values can be evaluated after processes with greater priority values.

Now being proud owners of a supporting process implementation, we are able to clean up our factory class´ code:

You probably have noticed that there is a new helper method to register applicable processes to the factory class. The method registerProcess() is overloaded and accepts either a System.Type instance or a String argument. If only a String is passed, the corresponding System.Type instance is automatically determined by calling the system.Type.forName(String typename) method.

The getInstance() method has significantly less lines of code. It now simply iterates over the list of registered System.Type instances, creates an instance for each registered process class and calls the MyProcessInterface.supports() method on them. Notice that the processes are checked in order of their priority, due to the call to the List.sort()  ethod (the list entries are only able to be sorted because the MyProcessInterface extends Comparable!)

Sorrily, it is not yet possible to perform static method calls on System.Type instances (so one might call supports() statically, which would avoid creating instances for each  process candidates in a first step).

Using the code above, we are now able to build an autotomatic process dispatcher within our visualforce component´s action controller:

Creating and registering new process implementations now as easy as implementing MyProcessInterface, registering the new process in the factory and creating the visualforce-page and -actioncontroller which only task is to call the underlying visualforce component and injecting the model data into it.

 

Concluding:
If you forgive me the somewhat senseless and very abstract „non- real-world“ sample — perhaps you are now able to take some advantages for yourself for future use cases where you have to dynamically decide between different implementations of the same code template/interface. Reflection is a very elegant way to minimize if/else constructs when instanciating objects based on varying input parameters and can assist you in very different situations and standard software design pattern conversion jobs.

The following two tabs change content below.

Johannes Heinen

Johannes ist einer der langjährigen Senior Entwickler bei Aptly und hat neben weitreichenden Salesforce Kenntnissen auch einen Satz Kreativität, um Produkte je nach individuellen Anforderungen selbst zu kreieren.

Neueste Artikel von Johannes Heinen (alle ansehen)

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.