I'm trying to use the java jcommander library from Scala. The java JCommander class has multiple constructors:
public JCommander(Object object) public JCommander(Object object, ResourceBundle bundle, String... args) public JCommander(Object object, String... args)
I want to to call the first constructor that takes no varargs. I tried:
jCommander = new JCommander(cmdLineArgs)
I get the error:
error: ambiguous reference to overloaded definition, both constructor JCommander in class JCommander of type (x$1: Any,x$2: <repeated...>[java.lang.String])com.beust.jcommander.JCommander and constructor JCommander in class JCommander of type (x$1: Any)com.beust.jcommander.JCommander match argument types (com.lasic.CommandLineArgs) and expected result type com.beust.jcommander.JCommander jCommander = new JCommander(cmdLineArgs)
I've also tried using a named parameter, but got the same result:
jCommander = new JCommander(`object` = cmdLineArgs)
How do I tell Scala I want to call the constructor that doesn't take varargs?
I'm using Scala 2.8.0.
Sorry, I now realize this is a known interoperability problem with Java. See this question and the ticket. The only work around I know of is to create a small Java class just to disambiguate these calls.
The only Scala solution to this problem that I know involves reflection.
Let's suppose we have a Java test class:
public class Ambig { public Ambig() {} public String say(Object o) { return o.toString(); } public String say(Object o, String... ss) { return o.toString()+ss.length; } }
We can get access to the method via reflection directly:
val ambig = new Ambig val methods = ambig.getClass.getMethods.filter(_.getName == "say") val wanted = methods.find(_.getParameterTypes.length == 1).get wanted.invoke(ambig, Some(5)).asInstanceOf[String]
or we can use structural types (which use reflection under the hood) to achieve the same thing with less boilerplate:
def sayer(speaker: { def say(o: Object): String }, o: Object) = speaker.say(o) sayer(new Ambig, Some(5))
Our strategy has to differ because we don't actually have an object to begin with. Let's suppose we have the Java class
public class Ambig2 { public final String say; public Ambig2(Object o) { say = o.toString(); } public Ambig2(Object o, String... ss) { say = o.toString()+ss.length; } }
The structural types approach no longer works, but we can still use reflection:
val mkAmbig2 = classOf[Ambig2].getConstructors.filter(_.getParameterTypes.length==1) val ambig = mkAmbig2.head.newInstance(Some(5)).asInstanceOf[Ambig2] ambig.say // Some(5)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With