Jaspersoft Studio Expression Editor: how to extend it and contribute your own functions (part 2)

Overview

PLEASE CONSIDER THAT THIS TUTORIAL IS NOW OUTDATED. YOU CAN ACCESS THE MOST RECENT ONE CLICKING ON:

Jaspersoft Studio Expression Editor: how to extend it and contribute your own functions (part 2) - updated for JSS 5.5.

If you haven't already, please read the introduction to the new Expression Editor in the first part of this tutorial.

In this section, we will cover some of the internal workings of the Functions Library. We will explain how it is implemented and how a developer can extend it in order to contribute his own functions in the environment.


Implementation Details

The best way to understand how the Function Library works and how to extend it is to access the source code and start looking at it. The source code is available from the public SVN repository at the following address:

http://anonsvn:anonsvn@code.jaspersoft.com/svn/repos/jasperreportsexpressions/

From this URL you can download two projects:

  • net.sf.jasperreports.expressions: contains the basic stuff like the dedicated JasperReports Extensions Registry (and Factory), the annotation classes and an utility class to work with them;

  • net.sf.jasperreports.expressions.functions: contains the built-in functions that we provide categorized in different classes, an utility class to manipulate them, plus the jasperreports_extension.properties file;

So JasperReports Extensions mechanism and Java Annotations are two key concepts behind the Functions Library:

  • net.sf.jasperreports.expressions.ExprFunctionsRegistry: this extension registry is used to collect generic classes that contain the implementations of the methods that will be proposed as functions in the expression editor;
  • net.sf.jasperreports.expressions.ExprFunctionsRegistryFactory: the extension registry factory class as specified in the jasperreports_extension.properties file. The registry_id chosen is expression.functions.

  • net.sf.jasperreports.expressions.annotations.JRExprFunction: annotation used to mark a function;

  • net.sf.jasperreports.expressions.annotations.JRExprFunctionCategories: annotation used to list the set of categories to which a function can belong to;

  • net.sf.jasperreports.expressions.annotations.JRExprFunctionParameter: annotation used to specify a parameter associated to a function;

  • net.sf.jasperreports.expressions.annotations.JRExprFunctionParameters: annotation used to list the set of parameters that a function can use;

Besides these classes, those ones that contain the "functions implementation" are inside the project net.sf.jasperreports.expressions.functions and are listed below:

  • net.sf.jasperreports.expressions.functions.DateTimeFunctions: contains the functions belonging to the category Built-in Functions > Date & Time

  • net.sf.jasperreports.expressions.functions.LogicalFunctions: contains the functions belonging to the category Built-in Functions > Logical

  • net.sf.jasperreports.expressions.functions.MathFunctions: contains the functions belonging to the category Built-in Functions > Numeric / Mathematical

  • net.sf.jasperreports.expressions.functions.TextFunctions: contains the functions belonging to the category Built-in Functions > Text

As you may have noticed this list is exactly the same present as property net.sf.jasperreports.extension.expression.functions.classes.stdlib.

At this point, you may have figure out that in order to contribute your own functions it's a matter of writing your Java class(es) and list them into .properties file. First of all let's give a look at how a function should be written looking into an existing one, then as a further step we will create a new function that will be contributed to the expression editor.

Dissecting a standard library function

For our analysis we will use the WEEKDAY function that as the description states "Returns the day of the week for a given date. Date object can be a String, long value (millis) or Date instance itself."

This is how it appears in the expression editor with some valid values already set:

Please note that the only mandatory parameter is the Date object that is highlighted in the red box (there is a star in top right corner of the description label). The second parameter is optional and it specifies if Sunday should be considered as first day of the week (default is not).

Let's now give a look at the code snippet subtending this function.

As you can see there are two methods WEEKDAY: the first one has the only mandatory parameter, while the second one exhibits also the optional Boolean parameter. The rule of thumb, when you create a new function, is that you should enrich with annotations the base method that has mandatory parameters with all the necessary information. Looking at the example above, you see that this includes the use of:

  • JRExprFunction: basic information on the function, like its name and description;
  • JRExprFunctionCategories: the category to wich the function belongs to;
  • JRExprFunctionParameters: the list of JRExprFunctionParameter (name and description) elements representing all the parameters, both mandatory and optional;

This quick overview of a standard library function should be enough to allow us to do right now a step forward. Let's then implement and contribute a new function that will be available in the expression editor.

Contributing a new function

Following what we have presented in the previous section, we will now proceed creating a new Java Project where it will be possible to start coding our new function(s).

Your work environment will look similar to the following one:

Summarizing these are the steps that should be performed:

  • Create a Java Project "CustomExpressionFunctions"

  • Add via "Java Build Path" the libraries jasperreports-expressions-x.y.z.jar and jasperreports-exprfunctions-x.y.z.jar. They can be found in the dist folder of the related projects.

  • Create a Java Class net.sf.jasperreports.expressions.functions.tests.CustomFunctions that contains the code for the function REPEATMESSAGE

    // ===================== REPEATMESSAGE function ===================== //
    @JRExprFunction(
       name="REPEATMESSAGE",
       description="Prints out the same message for the specified number of times. The final string is returned.")
    @JRExprFunctionCategories({"Dummy functions"})
    @JRExprFunctionParameters({
    @JRExprFunctionParameter(name="Message",description="The text message to be printed."), 
    @JRExprFunctionParameter(name="N. times",description="The number of times that the message should be printed.")})
    public static String REPEATMESSAGE(String message, Integer num){
        if(num <= 0){
            throw new JRExpressionFunctionException("You should print the message at least 1 time.");
        }
        StringBuffer buf=new StringBuffer();
        while(num>0){
            buf.append(message).append("\n");
            num--;
        }
        return buf.toString();
    }
  • Create a jasperreports_extension.properties file that contains the mandatory information:

    net.sf.jasperreports.extension.registry.factory.expression.functions=net.sf.jasperreports.expressions.ExprFunctionsRegistryFactory
    net.sf.jasperreports.extension.expression.functions.classes.test=net.sf.jasperreports.expressions.functions.tests.CustomFunctions
  • Package all the stuff into a jar file that can then be attached to our report project.

Moving to our Jaspersoft Studio runtime environment, the first thing to do is to add the previously exported jar as library. This can of course be done via "Java Build Path" section.

Once this is done, next time you will open the expression editor you will be able to use the newly contributed function:

As you can see you can create a simple report that allows you to see your brand-new function in action. This is a very simple example of how it will looks like:

Easy, isn't it?


Conclusions

This tutorial has shown how easy and simple is to extend the new Jaspersoft Studio Expression Editor. This kind of task is of course requires technical skills that a normal business report designer may not have. Right now, the user, besides having understood some of the internals, has also the required basic know-how to start coding its own custom functions that may range from simple operations to complex calculations.

In a new upcoming tutorial we will give a look at some of the extension-points behind the Expression Editor, in order to better understand some of the Jaspersoft Studio contribution mechanisms.

Feedback