3
votes

I want to call an overloaded Java method from Clojure, and passing in null (or nil in Clojure) has special meaning. How would I ensure that the correct Java method is called if the argument is nil?

e.g. suppose the overloaded Java methods were as follows:

public class Foo {
    public String bar(String s) {
        return (s == null) ? "default" : s;
    }

    public String bar(Integer i) {
        return (i == null) ? "0" : i.toString();
    }
}

I want to yield the value "default", so I want to do the following in my Clojure code:

(.bar (Foo.) (cast String nil))

I've tested this in two slightly different environments and I do not get consistent results. And it appears that casting a nil value in Clojure does not yield the expected type, e.g. --

(type (cast String nil))
; => nil
1
Interesting. How would you expect this to resolve in Java? - Bob Jarvis - Reinstate Monica
In Java it is possible to just do new Foo().bar((String) null); which ensures the correct overloaded method is called (i.e. the one with String in its method signature). - pestrella
A type hint might do the trick. See the accepted answer to stackoverflow.com/questions/2722856/… - nberger
Thanks @nberger, type hinting did the trick :D - pestrella

1 Answers

4
votes

cast doesn't do what you think it just ensures the second argument is of the specified class and returns it (the 2nd argument, not the class) or throws an exception.

You need to add a type hint but you can't add it directly to nil:

=> (String. nil)
CompilerException java.lang.IllegalArgumentException: More than one matching method found: java.lang.String

Here I have an exception because nil matches too many overloads and the compiler doesn't know which to pick.

=> (let [^String cnil nil] (String. cnil))
NullPointerException   java.lang.String.<init> (String.java:152)

Here I have an exception but from the constructor: the type hint allowed the compiler to select the proper overload (which overload complains about being passed a nil...).