Chapter 17. Java™ Binding

The Java binding feature is a powerful extensibility mechanism which allows direct calling of Java methods bound as XQuery functions and manipulation of wrapped Java objects.

Java Binding opens a tremendous range of possibilities since nearly all the Java APIs become accessible. The implementation performs many automatic conversions, including Java arrays and some Java collections.

The Java binding mechanism is widely used in several XQuery extension modules such as XML Library handling functions and SQL Connectivity.

Qizx Java Binding is similar to the mechanism introduced by several other XQuery or XSLT engines like XT or Saxon: a qualified function name where the namespace URI starts with "java:" is automatically treated as a call to a Java method.

In the following example the getInstance() method of the class java.util.Calendar is called:

declare namespace cal = "java:java.util.Calendar"
cal:get-instance()    (:  or cal:getInstance()  :)

The mechanism is actually a bit more flexible: a namespace can also refer to a package instead of a class name. The class name is passed as a prefix of the function name, separated by a dot. For example:

declare namespace util = "java:java.util"
util:Calendar.get-instance()

The following example invokes a constructor, gets a wrapped File in variable $f, then invokes the non-static method mkdir():

declare namespace file = "java:java.io.File"

let $f := file:new("mynewdir")   
return file:mkdir($f)  

In this example we list the files of the current directory with their sizes and convert the results into XML :

declare namespace file = "java:java.io.File"

for $f in file:listFiles( file:new(".") )    (: or list-files() :)
return 
    <file name="{ $f }" size="{ file:length($f) }"/>
Security:

The use of Java Binding in a server environment is a potential security vulnerability. Therefore Java Binding is not allowed by default in the API (applications Qizx Studio and command-line tool enable it).

Binding can be enabled on a class by class basis. To allow binding of a specific class, use the method enableJavaBinding in interface XQuerySession.

Static and instance methods:

A static Java method must be called with the exact number of parameters of its declaration.

A non-static method is treated like a static method with an additional first argument ('this'). The additional first actual argument must of course match the class of the method.

Constructors:

A constructor of a class is invoked by using the special function name "new". A wrapped instance of the class is returned and can be handled in XQuery and passed to other Java functions or to user-defined XQuery functions. For example:

declare namespace file = "java:java.io.File";
 file:new("afile.txt") 

Overloading on constructors is possible in the same way as on other methods.

Wrapped Java objects

Bound Java functions can return objects of arbitrary classes which can then be passed as arguments to other functions or stored in variables. The type of such objects is xdt:object (formerly xs:wrappedObject). It is always possible to get the string value of such an object (invokes the Java method toString()).

Type conversions:

Parameters are automatically converted from XQuery types to Java types. Conversely, the return value is converted from Java type to a XQuery type.

Basic Java types are converted to/from corresponding XQuery basic types.

Since the XQuery language handles sequences of items, special care is given to Java arrays which are mapped to and from XQuery sequences. In addition, a Vector, ArrayList or Enumeration returned by a Java method is converted to a XQuery sequence (each element is converted individually to a XQuery object).

The type conversion chart below details type conversions.

Overloading

Overloaded Java methods are partially supported:

  • When two Java methods differ by the number of arguments, there is no difficulty. XQuery allows functions with the same name and different numbers of arguments.

  • When two Java methods have the same name and the same number of arguments, there is no absolute guaranty which method will be called, because XQuery is a weakly typed language, so it is not always possible to resolve the method based on static XQuery types (Resolution at run-time would be possible but much more complex and possibly fairly inefficient).

    However, static argument types can be used to find the best matching Java method. For example, assume you bind the following class:

    class MyClass {
        String myMethod(String sarg) ... 
        int myMethod(double darg) ...
    }

    Then you can call the myMethod (or my-method) function in XQuery with arguments of known static type and be sure which Java method is actually called:

    declare namespace myc = "java:MyClass"
    myc:my-method(1)   (: second Java method is called :)
    myc:my-method("string")   (: first Java method is called :)
    1. in the first call, the argument type is xs:integer for which the closest match is Java double, so the second method is called.

    2. In the second call, the argument type is xs:string which matches String perfectly, so the first method is called.

    Of course it is possible to use XQuery type declarations, or constructs like cast as or treat as to statically specify the type of arguments:

    declare function local:fun($s as xs:string) {
       myc:my-method($s)   (: first Java method is called :)
    }

    or:

     myc:my-method($s treat as xs:string)   (: first Java method is called :)

    Limitations

    There are still some limitations when in both methods the argument types is any non-mappable Java class (xdt:object in XQuery):

    class MyClass {
        Object myMethod2(ClassA arg) ... 
        int    myMethod2(ClassB arg) ...
    }

    In that case there is currently no way in Qizx to specify the static type of the actual argument, so the result is unpredictable and may result in a run-time error.

Table 17.1. Types conversions

Java typeXML Query type
void (return type)empty()
Stringxs:string
boolean, Booleanxs:boolean
double, Doublexs:double
float, Floatxs:float
java.math.BigDecimal, java.math.BigIntegerxs:decimal
long, Longxs:integer
int, Integerxs:int
short, Shortxs:short
byte, Bytexs:byte
char, Characterxs:integer
com.qizx.api.Nodenode() ?
org.w3c.dom.Nodenode() ?
java.util.Date, java.util.Calendarxs:dateTime ?
other classxdt:object ?
String[ ]xs:string *
double[ ], float[ ]xs:double *
long[ ], int[ ], short[ ], byte[ ], char[ ]xs:integer *
com.qizx.api.Node[ ]node()*
other arrayxdt:object *
java.util.Enumeration, java.util.Vector, java.util.ArrayList (return value only)xdt:object *