Using Java Functions


DataDirect XQuery supports Java static methods, Java instance methods, and Java constructors.

The DataDirect XQuery type ddtek:javaObject allows you to invoke Java methods. The predeclared DataDirect XQuery namespace prefix is ddtek, and is bound to http://www.datadirect.com/xquery. The examples in this section demonstrate the usage of ddtek:javaObject.

Declaring Java Functions

Two steps are required to declare Java functions:

  1. Import the class into the XQuery environment.
  2. Declare the function.

1. Importing the Class

Before you can declare a Java class, you must import it into the XQuery environment. To do this, you must declare a namespace with a specific URL. The syntax of an import is:

declare namespace prefix = "ddtekjava:java class name"; 

where:

prefix is a namespace prefix to associate with the Java class.

java class name contains the complete package and class name of the Java class to import. The specified Java class must be accessed using the Java class loader in the environment in which the query is executed. Typically, this means that the CLASSPATH must contain a reference to the directory or jar file where the Java class can be found. In J2EE server environments, other requirements may exist such as the jar or class file must be stored in a specific directory.

For example:

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

If DataDirect XQuery cannot find the Java class, it generates a static error.

2. Declaring the Function

Before you can invoke a Java function in a query, you must declare it. How you declare it depends on whether the Java function is a static method or an instance method.

Static Method

To declare a static method, use the following syntax:

declare namespace file = "ddtekjava:java.io.File"; 
declare function namespace:function name(argument list) as return type 
  external; 

For example:

declare function file:createTempFile($prefix as xs:string,$suffix as 
  xs:string) as ddtek:javaObject external; 

See also "Example: Java Function (Static Method)".

Instance method

To declare an instance method, follow these steps:

  1. Import the class to a namespace (see "1. Importing the Class").
  2. In the cases where you need to explicitly create a new Java object instance, declare a function mapping to a Java constructor unless the Java object type you are declaring has a defined XQuery mapping. A class instance can be an XML type for which a mapping is defined.
  3. Declare a function mapping to an instance method declaring ddtek:javaObject as the value for the first parameter if Step 2 is required. Otherwise, the value of the first parameter is the appropriate XQuery data type.
  4. Invoke the function using the class instance on which the instance method is invoked as the first argument.

The numbers in the following example correspond to the preceding steps:

declare namespace BigInteger = "ddtekjava:java.math.BigInteger"; 1 
declare function BigInteger:BigInteger($v as xs:string) 2 
    as ddtek:javaObject external; 
declare function BigInteger:gcd(  
    $this as ddtek:javaObject,  
    $val as xs:integer) as xs:integer external; 3 
 
    BigInteger:gcd(BigInteger:BigInteger("12"),4) 4 

The following example does not include Step 2 because the Java object to be declared has a defined XQuery mapping.

declare namespace BigInteger = "ddtekjava:java.math.BigInteger"; 1 
    declare function BigInteger:gcd( 
      $this as xs:integer,  
      $val as xs:integer) as xs:integer external; 3 
 
     BigInteger:gcd(12,4) 4 

Mapping Types Between Java and XQuery for Java External Functions

Before DataDirect XQuery passes XQuery arguments to a Java method, it converts the arguments from the XQuery data type to a Java type using the SequenceType specified for the external function when it was declared.

Table 10-1 shows how to map arguments and return types from the Java function declaration to XQuery SequenceTypes to be used in the XQuery function declaration.

Table 10-1. Mapping Types Between Java and XQuery  
Java
XQuery
boolean
xs:boolean
byte
xs:byte
byte[]
ddtek:javaObject
xs:base64binary
xs:hexBinary
double
xs:double
float
xs:float
int
xs:int
long
xs:long
short
xs:short
javax.xml.transform.Source1
ddtek:javaObject
document-node( )
java.lang.Boolean
ddtek:javaObject
xs:boolean[?]
java.math.BigDecimal
ddtek:javaObject
xs:decimal[?]
java.math.BigInteger
ddtek:javaObject
xs:integer[?]
java.lang.Byte
ddtek:javaObject
xs:byte[?]
java.lang.Double
ddtek:javaObject
xs:double[?]
java.lang.Short
ddtek:javaObject
xs:short[?]
java.lang.Long
ddtek:javaObject
xs:long[?]
java.lang.Integer
ddtek:javaObject
xs:int[?]
java.lang.Float
ddtek:javaObject
xs:float[?]
java.lang.String
ddtek:javaObject
xs:untypedAtomic[?]
xs:string[?]
java.net.URI
ddtek:javaObject
xs:anyURI[?]
java.xml.namespace.QName
ddtek:javaObject
xs:QName[?]
org.w3c.dom.Attr
ddtek:javaObject
attribute() [?]
org.w3c.dom.Comment
ddtek:javaObject
comment() [?]
org.w3c.dom.Document
ddtek:javaObject
document-node() [?]
org.w3c.dom.Element
ddtek:javaObject
element() [?]
org.w3c.dom.Node
ddtek:javaObject
document-node() [?]
element() [?]
attribute() [?]
comment() [?]
text() [?]
processing-instruction() [?]
org.w3c.doc.ProcessingInstruction
ddtek:javaObject
processing-instruction() [?]
org.w3c.dom.Text
ddtek:javaObject
text() [?]
java.lang.Object 2
ddtek:javaObject
void
empty-sequence() 3
boolean, byte, double, float, int, long, short 4
xs:anyAtomicType? 4
byte[], java.math.BigDecimal, java.math.BigInteger, java.lang.Byte, java.lang.Double, java.lang.Float, java.lang.Integer, java.lang.Long, java.lang.Short, java.lang.String, java.net.URI, java.xml.namespace.QName
xs:anyAtomicType? 4
Any Java data type in this table
item() 4
Any Java object type in this table
item() ? 4
Any Java type in this table
item()* 3
item() + 3
java type [] 5
ddtek:javaObject
XQuery type of this table(*|+)
1 Must be one of the following interfaces: javax.xml.transform.stream.StreamSource, javax.xml.transform.sax.SAXSource, javax.xml.transform.dom.DOMSource, javax.xml.transform.stax.StAXSource, or com.ddtek.xquery.StAXSource.
2 java.lang.Object or another Java class not listed in this table.
3 Only for return types.
4 Useful to declare Java methods overloaded on argument type. See "Resolving Function Calls".
5 When the Java parameter type or method return type is an array, either declare the XQuery function to receive or return one of the matching types from this table and add a * or + quantifier.You can also use ddtek:javaObject with a * or + quantifier.

In cases where Table 10-1 lists multiple mapping options, consider the following information:

Resolving Function Calls

Before DataDirect XQuery attempts to resolve the Java method to invoke for a given XQuery function call, DataDirect XQuery identifies the external function declaration.

Then, like any other XQuery function call, the static types of the argument expressions are matched with the SequenceType of the function declaration parameters. Static type errors are detected and reported.

Finally, the Java method must be resolved. Sometimes, DataDirect XQuery cannot determine how to map an XQuery function declaration and the associated function call to a Java instance method. Ambiguity can occur for the following reasons:

DataDirect XQuery uses the following steps to determine the Java method to invoke for a given function call. Except for the first step, each of the consecutive steps reduces the number of Java functions that are potential candidates to which to map the XQuery function call.

  1. Add all public (static and instance) methods and public constructors of the Java class identified through the function’s namespace.
  2. Use a public constructor if the name of the function equals the class name. In the absence of matching public constructors, DataDirect XQuery considers Java methods with the same name.
  3. Retain only Java methods whose names match the name of the function if the name of the function being invoked does not equal the class name.
  4. Remove all instance methods, unless the first argument in the function call is typed as ddtek:javaObject and the Java class associated with the ddtek:javaObject equals the class identified by the namespace of the function (see "Notes About Using Java Instance Methods").
  5. Remove all static methods and constructors whose number of parameters does not match the number of parameters in the XQuery function declaration.
  6. Remove all instance methods whose number of parameters does not equal the number of parameters of the XQuery function declaration minus one (this takes into account the first artificial "this" argument that is required when invoking an instance method from XQuery).
  7. Remove all Java methods and constructors for which the SequenceType of the argument as specified in the function declaration does not match the type of the Java method. The type matching requires a mapping from an XQuery SequenceType to a Java type. This mapping is documented in Table 10-1. Note that when the function argument is declared as item(), xs:anyAtomicType, or ddtek:javaObject, DataDirect uses the static type of the argument expression of the function call instead of the SequenceType of the function declaration. This typically is more accurate and allows correct method resolution in more scenarios.

Unless exactly one method remains after the previously described procedure, one of the following static errors is generated:

Static error during resolving of external Java function. 
Ambiguous call to Java external function '<function>' 

or

Static error during resolving of external Java function. No 
matching Java external function found for '<function>' 

Note that at execution time:

NOTE: Generic methods introduced with J2SE 5.0 are not supported.

Notes About Using Java Instance Methods

See also "Resolving Function Calls".

Disabling Java Functions

You can disable the ability to invoke Java functions, for example, for security reasons, by specifying the AllowJavaFunctions property of DDXQDataSource. See "DDXQDataSource and DDXQJDBCConnection Properties".