Extending the Expression Language
The function language can be extended to support any user-defined scalar valued functions or aggregations.
To create your own function, create a class containing methods that return your scalar valued functions or aggregations. Mark each of these methods with the
@Function annotation.
You may optionally specify the following properties for the
@Function annotation:
name
Specifies the identifier to use within the function language to identify this function. If not specified, the name of the method is used.
invoker
argumentCount
Specifies the number of arguments which the function language should expect when calling this function. If not specified, the number of method arguments is used.
description
Provides a description of the function, used in documentation.
argumentNames
Specifies an array of names for each argument the function takes. This only needs to be set if the number of function arguments does not match the number of method arguments; otherwise, specify this for each argument using the name property in
@FunctionArgument.
In most cases,
DefaultFunctionInvoker can be used to invoke a scalar valued function method. This invoker will expect the same number of arguments as the method takes.
ScalarValuedFunction method arguments are taken directly from the function call. If the method takes primitive or String arguments, the invoker will expect ConstantReference arguments of the appropriate type. For other argument types, you can specify a custom
ArgumentConverter for each argument using the
@FunctionArgument annotation.
@FunctionArgument optionally takes the following properties:
name
Specifies the name of the argument, used in documentation.
converter
description
Provides a description of the argument, used in documentation.
If your method takes a single List
<ScalarValuedFunction> argument, you may use the
ListFunctionInvoker invoker and specify an argumentCount of Function.VARIABLE_ARGUMENT_COUNT. This invoker will take any number of
ScalarValuedFunction arguments and pass them as a single list to the method.
If your method requires more complex arguments, you may create your own subclass of
FunctionInvoker.
It will require a single method, invoke, which takes two arguments, a Method to invoke, and an array of
ScalarValuedFunction arguments. Process the arguments as required and pass them to the method using the Method.invoke() call.
Once your functions have been defined, you can create a subclass of
SimpleFunctionProvider to register these method classes. Finally, add a file to META-INF/services called
com.pervasive.dataflow.functions.FunctionProvider, containing the fully qualified name of your
SimpleFunctionProvider subclass.
The same applies for aggregations, except you will create a subclass of
SimpleAggregationProvider, and the file you add to META-INF/services will be called
com.pervasive.dataflow.aggregations.AggregationProvider.
For more information about writing custom DataFlow functions, see
Writing a Function.