¿Cómo desambiguo en Scala entre los métodos con vararg y sin

Estoy tratando de usar la biblioteca java jcommander de Scala. La clase java JCommander tiene múltiples constructores:

public JCommander(Object object) public JCommander(Object object, ResourceBundle bundle, String... args) public JCommander(Object object, String... args) 

Quiero llamar al primer constructor que no toma varargs. Lo intenté:

 jCommander = new JCommander(cmdLineArgs) 

Me sale el error:

 error: ambiguous reference to overloaded definition, both constructor JCommander in class JCommander of type (x$1: Any,x$2: [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) 

También intenté usar un parámetro con nombre, pero obtuve el mismo resultado:

 jCommander = new JCommander(`object` = cmdLineArgs) 

¿Cómo le digo a Scala que quiero llamar al constructor que no toma varargs?

Estoy usando Scala 2.8.0.

Lo siento, ahora me doy cuenta de que este es un problema conocido de interoperabilidad con Java. Vea esta pregunta y el boleto . El único trabajo que conozco es crear una pequeña clase de Java para desambiguar estas llamadas.

La única solución de Scala a este problema que conozco implica reflexión.

Métodos ambiguos

Supongamos que tenemos una clase de prueba de Java:

 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; } } 

Podemos acceder al método directamente a través de la reflexión:

 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] 

o podemos usar tipos estructurales (que utilizan la reflexión debajo del capó) para lograr lo mismo con menos repetitivo:

 def sayer(speaker: { def say(o: Object): String }, o: Object) = speaker.say(o) sayer(new Ambig, Some(5)) 

Constructores ambiguos

Nuestra estrategia debe diferir porque en realidad no tenemos un objeto para empezar. Supongamos que tenemos la clase Java

 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; } } 

El enfoque de tipos estructurales ya no funciona, pero aún podemos usar la reflexión:

 val mkAmbig2 = classOf[Ambig2].getConstructors.filter(_.getParameterTypes.length==1) val ambig = mkAmbig2.head.newInstance(Some(5)).asInstanceOf[Ambig2] ambig.say // Some(5) 

Creo que su opción más fácil es tener una clase Java con un método de fábrica para resolver el problema:

 package com.beust.jcommander; public class JCommanderFactory { public static createWithArgs(Object cmdLineArgs) { return new JCommander(cmdLineArgs); } } 

Alternativamente, puede usar http://jewelcli.sourceforge.net/usage.html en su lugar. JewelCli tiene un método de fábrica inequívoco para el mismo propósito y también utiliza la técnica PICA (Interfaces Proxy configuradas con anotaciones) http://www.devx.com/Java/Article/42492/1954 .

De hecho, tengo un ejemplo del uso de JewelCLI con Scala aquí en Stack Overflow .

La forma de evitar esta ambigüedad es forzar al comstackdor a elegir la sobrecarga que requiere más de un argumento, utilizando la syntax de explosión de la colección de Scala para pasar en una colección singleton:

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