Menu

HOME > SUPPORT > CUSTOM FUNCTIONS

Custom Functions

 

Overview

Developers can add custom functions to ReportMill simply by implementing a static method that takes an Object arg (or args) in a class that is registered with ReportMill. Here's a sample that would allow developers to use a key like "@floor(getRevenue)@":

// Create a class with one or more static methods that accept Object args
public class RMAddOns {

  // This method accepts a single Object arg and returns the Math.floor()
  public static Object floor(Object anObj)
  {
    float value = anObj instanceof Number? ((Number)anObj).floatValue() : 0;
    return new Float(Math.floor(value));
  }
}

// Register class with ReportMill's RMKeyChain class
RMKeyChain.addFunctionClass(RMAddOns.class);

Custom Aggregate Functions

Developers can also add new aggregate methods to ReportMill simply by implementing a method that accepts a java.util.List arg and an RMKeyChain arg. Here's an example method that would let you use a key like "@myTotal.getRevenue@":

  // This method returns a total for a List and a KeyChain
  public static Object myTotal(List aList, RMKeyChain aKeyChain)
  {
    float total = 0;

    for(int i=0; i<aList.size(); i++)
      total += RMKeyChain.floatValueForKeyChain(aList.get(i), aKeyChain);

    return new Float(total);
  }

The RMKeyChain class is ReportMill's internal representation of arbitrary expressions, and the floatValueForKeyChain() method is used to evaluate the expression relative to a particular object.
The routine above, therefore, will work for "@myTotal.getRevenue@" as well as a more complex expression such as "@myTotal(getRevenueKind=="taxable" ? getRevenue/1.0825 : getRevenue)@".

Example 1 - Custom Formatting

One of the most common reasons to add a custom function to ReportMill is to provide some format that isn't supported natively by ReportMill. Here is an example of adding two methods to format a number or a date using the standard Java formatter classes DecimalFormat and DateForamt. These could then be invoked using the keys "@moneyFormat(getRevenue)@" and "@dateFormat(getShowDate)@".

// Create a class with one or more static methods that accept Object args
public static class RMAddOns {

  // This method accepts a single Object arg and returns a money formatted string
  public static Object moneyFormat(Object anObj)
  {
    double value = anObj instanceof Number? ((Number)anObj).doubleValue() : 0;
    return new DecimalFormat("$ #,##0.00").format(value);
  }

  // This method accepts a single Object arg and returns a date formatted string

  public static Object dateFormat(Object anObj)
  {
    Date value = anObj instanceof Date? (Date)anObj : null;
    return DateFormat.getDateInstance().format(value);
  }

}

Designer Integration

There currently isn't a great story for designer integration, such as a "Load External Custom Function Jars" panel, so often it won't be worth the effort to get such functions to show up just for the sake of preview. However, one possible solution would be to add a main() method to your custom function class that calls registerFunctionClass(), then calls com.reportmill.App.main(args). Then if you manually launched the designer using the RMStudio.jar and your function class main, the function would operate in the context of the designer.

prompt> java -cp RMStudio10.jar:. com.mycompany.RMExtraFunctions

The downside to launching the application manually like this is that you lose the auto-update feature that webstart provides. A solution to this might be to put your custom functions class in a jar in your Java library extensions directory, then launch the app using a modified version of the RMStudio jnlp file.