score:1

You can call the constructor with varags, but pass an empty list of varags.

(Of course, if you know that constructing JCommander with empty varags will produce the same result as calling the overloaded constructor (or method) without vargs)

jCommander = new JCommander(cmdLineArgs, Nil: _*)

score:2

The way to avoid this ambiguity is to force the compiler to pick the overload that takes more than one argument, using Scala's collection explosion syntax to pass in a singleton collection:

import java.util.stream.Stream
val stream = Stream.of(List(1):_*)

score:5

I think your easiest option is to have a Java class with a factory method to bridge the issue:

package com.beust.jcommander;

public class JCommanderFactory {
    public static createWithArgs(Object cmdLineArgs) {
        return new JCommander(cmdLineArgs);
    }
}

Alternatively you could use http://jewelcli.sourceforge.net/usage.html instead. JewelCli has an unambiguous factory method for the same purpose and also uses PICA (Proxied Interfaces Configured with Annotations) technique http://www.devx.com/Java/Article/42492/1954.

In fact I have an example of using JewelCLI with Scala here on Stack Overflow.

score:11

The only Scala solution to this problem that I know involves reflection.

Ambiguous Methods

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))

Ambiguous Constructors

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)

score:18

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.


Related Query

More Query from same tag