Choosing among overloaded methods
If there is no method with the required name and number of parameters, Saxon reports a compile-time error.
If there is only one method with the required name and number of parameters, then Saxon chooses it, and goes on to the next stage, which allocates converters for the supplied arguments.
If there are several methods in the class that match the localname, and that have the
correct number of arguments, then the system attempts to find the one that is the best fit
to the types of the supplied arguments: for example if the call is f(1,2)
then
a method with two int
arguments will be preferred to one with two
float
arguments. This decision is typically made during static type analysis.
The rules for deciding between methods are quite complex.
Essentially, for each candidate method, Saxon calculates the "distance" between the types of
the supplied arguments and the Java class of the corresponding method in the method's
signature, using a set of tables (see below). For example, the distance between the XPath data type
xs:integer
and the Java class long
is very small, while the
distance between an XPath xs:integer
and a Java Object
is much
larger. If there is one candidate method where the distances of all arguments are
less-than-or-equal-to the distances computed for other candidate methods, and the distance
of at least one argument is smaller, then that method is chosen.
If there are several methods with the same name and the correct number of arguments, but none is preferable to the others under these rules, an error is reported: the message indicates that there is more than one method that matches the function call.
This binding is carried out statically, using the static types of the supplied
arguments, not the dynamic types obtained when the arguments are evaluated. If there is
insufficient static type information to distinguish the candidate methods, an error is
reported. You can supply additional type information using the treat as
expression, or by casting. Often it is enough simply to declare the types of the variables
used as arguments to the function call.
The distances are calculated using the following rules (in order).
-
If the required type is
Object
, the distance is 100. -
If the required type is one of the following Saxon-specific classes (or is a superclass of that class), then the distance is as given:
Note that Saxon does not recognize the classes defined in the s9api package for use with extension functions (for example, XdmNode and XdmAtomicValue).
-
If the static type of the supplied argument allows more than one item, the distance is the first one of the following that applies:
-
If the method expects
java.lang.Collection
or a class that implementsCollection
: 30 -
If the method expects an array: 31
-
In all other cases: 80
Note that the item type of the supplied value plays no role in choosing the method to call, even though it could potentially be used to disambiguate overloaded methods when arrays or parameterized collection types are used.
-
-
Otherwise (the static type allows only one item):
-
If the static type of the supplied value matches
node()
: 80 -
If the static type of the supplied value is a wrapped Java object, then 10 if the class of the object matches the required Java class, else -1 (meaning this method is not a candidate)
-
Otherwise, the value given by the table of atomic types below.
-
For each of the atomic types listed below, the distance between the supplied type and the first corresponding required type (the Saxon-specific class in italics) is 50. Distances then increase (by 1 or 2) as you go along the ordered list of other possible required types. If there is no entry for the combination of supplied type and required type, the method is removed from consideration. For unboxed types (int, float, etc) the distance is always one less than the corresponding boxed type (java.lang.Integer, java.lang.Float).
Supplied type |
Required type |
xs:string |
StringValue, String, CharSequence |
xs:boolean |
BooleanValue, Boolean |
xs:float |
FloatValue, Float, Double |
xs:double |
DoubleValue, Double |
xs:decimal |
DecimalValue, BigDecimal, Double, Float |
xs:integer |
IntegerValue, BigInteger, BigDecimal, Long, Integer, Short, Byte, Double, Float |
xs:date, xs:gDay, xs:gMonthDay, xs:gMonth, xs:gYearMonth, xs: gYear |
DateValue, Date |
xs:dateTime |
DateTimeValue, Date |
xs:time |
TimeValue |
xs:duration, xs:yearMonthDuration, xs:dayTimeDuration |
DurationValue |
xs:hexBinary |
HexBinaryValue |
xs:base64Binary |
Base64BinaryValue |
xs:anyURI |
AnyURIValue, java.net.URI, java.net.URL, String, CharSequence |
xs:QName |
QNameValue, javax.xml.namespace.QName |
A required type of one of the Java primitive types such as int
or
bool
is treated as equivalent to the corresponding boxed type
(Integer
or Boolean
), except that with the boxed types, an empty
sequence can be supplied in the function call and is translated to a Java null value as the
actual argument.
The fact that a particular method is chosen as the target does not give a guarantee that conversion of the arguments will succeed at run-time. This is particularly true with methods that expect a node in an external object model such as DOM or XOM.