Calling Java Instance-Level Methods

There are two ways of calling instance-level methods (that is, non-static methods). In both cases you first need to get a value representing the Java object whose method is to be called: this will usually be obtained by invoking a constructor or static factory method, or it may be supplied as an external parameter to a stylesheet or query.

  1. From Saxon 9.9, an external Java object can be converted to an XDM map item. This conversion can be done explicitly using the saxon:object-map extension function; it is also done implicitly if the left-hand operand of the lookup operator "?" evaluates to an external Java object. The entries in the map are key-value pairs, and there is one entry for each public non-static method in the Java object, provided that it is not overloaded. The key of the entry is the method name, and the value of the entry is a function that can be invoked using a dynamic function call. So, for example, you can create an object of type javatype:java.net.URI using the code let $uri := Q{java:java.net.URI}new('https://saxonica.com/') and you can then find the "scheme' part of this URI with the expression $uri?getScheme() (which returns the xs:string value "https").

    In fact there will be two entries in the map for this method: getScheme and getScheme_0. The version with an arity suffix can be used where the class defines multiple methods having the same name but different arity. If there are two methods with the same name and the same arity, however, no entry is created and the method cannot be called. Note that there is no conversion of the name to hyphenated form: the method must be invoked as getScheme rather than get-scheme.

    The map produced to represent the object also has an entry with key "this" whose value is the original external object.

  2. The second way to call instance-level methods is as a regular (static) function call with an extra first argument. In this case matching of method names is done as for static methods. If there are several methods in the class that match the localname, the system again tries to find the one that is the best fit, according to the types of the supplied arguments (see Choosing among overloaded methods.

    For example, the following XSLT stylesheet prints the date and time. (From XSLT 2.0, of course, this no longer requires extension functions, but the example is still valid.)

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:date="java:java.util.Date"> <xsl:template match="/"> <html> <xsl:if test="function-available('date:to-string') and function-available('date:new')"> <p><xsl:value-of select="date:to-string(date:new())"/></p> </xsl:if> </html> </xsl:template> </xsl:stylesheet>

    The equivalent in XQuery is:

    declare namespace date="java:java.util.Date"; <p>{date:to-string(date:new())}</p>

As with static methods, an instance-level Java method called as an extension function may have an extra first argument of class net.sf.saxon.expr.XPathContext. This argument is not supplied by the calling XPath or XQuery code, but by Saxon itself. The XPathContext object provides methods to access many internal Saxon resources, the most useful being getContextItem() which returns the context item from the dynamic context. The XPathContext object is not available with constructors.

If any exceptions are thrown by the method, or if a matching method cannot be found, processing of the stylesheet will be abandoned. If the tracing option -T has been set on the command line, a full stack trace will be output. The exception will be wrapped in a TransformerException and passed to any user-specified ErrorListener object, so the ErrorListener can also produce extra diagnostics.

It is also possible to use the reflexive call mechanism to call instance-level methods of the implementation classes for XDM values. For example, the following gets the current Julian instant as a decimal number:

<xsl:value-of select="d:toJulianInstant(current-dateTime())" xmlns:d="java:net.sf.saxon.value.DateTimeValue"/>

This will only work if the value of the expression (current-dateTime() in this example) is implemented internally as an instance of the class defined in the namespace used to invoke the method. Using this mechanism successfully therefore requires some knowledge of the Saxon internals.