Custom functions are basically those specified by the developer to extend the JoSQL functionality in some way. Custom functions can override the built-in functions (see below for details of the search order for functions) to provide differing functionality if required.
To create your own function(s) is trivial. Any public method from any object can be used.
For example, to create a
to_string
function that will operate on the "current object" (see
Current Object Scope), it should have a signature thus:
public String to_string (Object o)
This would then be referred to in the SQL via:
SELECT to_string (12345)
FROM java.lang.Object
or:
SELECT *
FROM java.lang.Object
WHERE toString = to_string (toString)
The custom function can throw any exception, if one is thrown this is wrapped in an instance of:
org.josql.QueryExecutionException
.
JoSQL tries (wherever possible) to get the "best" match of the arguments to a function to the underlying Java method. However, it also tries to provide flexibility to the developer in that it also allows the developer to take control of how the arguments are handled.
For example, if you use define a function method as:
public Object myFunction (Getter acc)
And then call the function:
SELECT myFunction (name)
FROM java.io.File
then JoSQL will detect that you actually want the Getter object that represents the access to the
getName
method in the
java.io.File
class rather than the value. However if you define your function method as:
public Object myFunction (Object o)
Then JoSQL will execute the Getter for you on the current object and pass the result to the function method instead.
Similarly with functions as arguments, if your function is defined as:
public Object myFunction (List objs,
Function f)
And call from the SQL with:
SELECT myFunction (:_allobjs, toDate (name))
FROM java.io.File
Then JoSQL will pass the Function object to the function method instead so that you can execute yourself. Note that to execute a Function expression you must have access to the Query object as well.
However if you defined your function method as:
public Object myFunction (List objs,
Object o)
And call from the SQL with:
SELECT myFunction (:_allobjs, toDate (name))
FROM java.io.File
then JoSQL will execute the
toDate(name)
function first and then call the
myFunction
with the result.
The basic rule is that if you wish to have "control" over how the Getter or Function is executed, for example if you wish to execute it over a specific set of objects then use a Getter or Function argument, otherwise use
java.lang.Object
or a more specific class.
It is also possible to have an "expression" (
org.josql.expressions.Expression
) passed to the function. Again JoSQL will detect this when matching up the arguments and pass the Expression object rather than the result of evaluating the expression. In this case it is important to know that Expressions use the "current object" and thus this needs to be set via:
Query.setCurrentObject(Object)
prior to evaluating the expression, AND the current object that was in place prior to execution of the function needs to be "put back" before leaving the function otherwise strange behaviour could result. In general, this advanced aspect of JoSQL shouldn't really be performed unless you have a VERY good reason to do so. See the source for:
org.josql.functions.CollectionFunctions.count(List,Expression)
for an example of how expressions can be evaluated and handled in a function.
Custom functions are searched for in the order in which their "handler Object" are added to the Query object.
For example:
Query q = new Query ();
q.addFunctionHandler (new MyFunctionHandler1 ());
q.addFunctionHandler (new MyFunctionHandler2 ());
The instance of
MyFunctionHandler1
would thus be search first for the custom function and then the instance of:
MyFunctionHandler2
.
Note: if JoSQL finds the function in
MyFunctionHandler1
it will NOT then search
MyFunctionHandler2
.
Also, JoSQL only searches within the direct public methods of the handler object, superclass/superinterface methods are NOT searched.
All functions are searched for in the custom handlers first before the built-in handlers are checked, in this way you can easily override the operation of any of the built-in functions with ease.