Converting wrapped Java objects
Saxon allows an extension function to return an arbitrary Java object. This will then be wrapped as an XPath item, so that it can be held in a variable and passed subsequently as an argument to another extension function. This second extension function will see the original Java object minus its wrapper, provided it is declared to expect the appropriate Java class.
A wrapped Java object always holds a non-null object value. The Java value null converts to the XPath empty sequence.
A wrapped Java object may be converted to another data type as follows.
-
It is converted to a string by calling its
toString()
method. -
It is atomized by calling its
toString()
method. -
It is converted to a number by converting it first to a string, and then applying the XPath
number()
conversion. -
The effective boolean value of a wrapped Java object (like that of a node) is always true.
The type of a wrapped Java object may be declared in a variable declaration or function
signature using a type name whose namespace URI is http://saxon.sf.net/java-type
, and
whose local name is the fully qualified name of the Java class, with any "$" signs replaced
by hyphens, and with leading "[" characters replaced by "_-". For example, the
sql:connection
extension function returns a value of type
{http://saxon.sf.net/java-type}java.sql.Connection
.
Note that a call on a constructor function (using prefix:new()
) always returns a wrapped
Java object, regardless of the class. But a call on a static method, instance-level method,
or field will return a wrapped Java object only if the result is a class that Saxon does not
specifically recognize as one that it can convert to a regular XPath value. Such classes
include String
, Long
, Double
, Date
,
BigInteger
, URI
, List
, Map
, and so on.
If you want an object of one of these "recognized" classes to be returned as a wrapped Java object
rather than being converted to its XDM equivalent (for example, if you want a Java java.util.List
kept as an instance of java.util.List
, rather than being converted to an XDM Sequence),
you can achieve this by binding the result of a function call to a variable that declares the required
type (or by using it as an argument of a function call whose signature defines the required type).
For example if you write <xsl:variable name="list" select="Q{java:java.util.Collections}emptyList()"/>
then the result will be an XDM empty sequence. But if you add the attribute as="jt:java.util.List"
,
where the prefix jt
is bound to the namespace http://saxon.sf.net/java-type
, then
the conversion to an XDM sequence will be prevented, and the result will be a wrapped Java object of type
java.util.List
.
A wrapped Java object is also used in an expression such as Q{java:java.util.List}size(my:bigList())
,
where Saxon knows that the first argument to size() must be an instance of java.util.List
,
or Q{java:java.lang.String}split('a,b,c', ',')
where it knows that split
requires a Java string (this means that the XPath xs:string
value is converted to a wrapped Java object
of class java.lang.String
).
In Saxon 9.4 and earlier releases, a wrapped Java object was considered to be an atomic
value (in the XDM type hierarchy, the type representing java.lang.Object
was a
peer of primitive types such as xs:string
and xs:boolean
). In Saxon
9.5, this changed so that wrapped objects are a fourth subtype of item()
, at
the same level in the type hierarchy as nodes, atomic values, and function items. Atomizing
a wrapped Java object produces an instance of xs:string
containing the
result of the toString()
method applied to the underlying object.