Ответ 1
Извините, теперь я понимаю, что это известная проблема совместимости с Java. См. этот вопрос и билет. Единственная работа, о которой я знаю, - создать небольшой Java-класс, чтобы просто устранить эти вызовы.
Я пытаюсь использовать библиотеку java jcommander из Scala. Класс java JCommander имеет несколько конструкторов:
public JCommander(Object object)
public JCommander(Object object, ResourceBundle bundle, String... args)
public JCommander(Object object, String... args)
Я хочу вызвать первый конструктор, который принимает no varargs. Я пробовал:
jCommander = new JCommander(cmdLineArgs)
Я получаю сообщение об ошибке:
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)
Я также попытался использовать именованный параметр, но получил тот же результат:
jCommander = new JCommander(`object` = cmdLineArgs)
Как сообщить Scala Я хочу вызвать конструктор, который не принимает varargs?
Я использую Scala 2.8.0.
Извините, теперь я понимаю, что это известная проблема совместимости с Java. См. этот вопрос и билет. Единственная работа, о которой я знаю, - создать небольшой Java-класс, чтобы просто устранить эти вызовы.
Единственное решение Scala для этой проблемы, которое, как я знаю, включает отражение.
Предположим, что у нас есть тестовый класс 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; }
}
Мы можем получить доступ к методу через отражение напрямую:
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]
или мы можем использовать структурные типы (которые используют отражение под капотом) для достижения того же самого результата с меньшим количеством шаблонов:
def sayer(speaker: { def say(o: Object): String }, o: Object) = speaker.say(o)
sayer(new Ambig, Some(5))
Наша стратегия должна отличаться, потому что на самом деле у нас нет объекта для начала. Предположим, что мы имеем класс 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; }
}
Подход структурных типов больше не работает, но мы все еще можем использовать отражение:
val mkAmbig2 = classOf[Ambig2].getConstructors.filter(_.getParameterTypes.length==1)
val ambig = mkAmbig2.head.newInstance(Some(5)).asInstanceOf[Ambig2]
ambig.say // Some(5)
Я думаю, что ваш самый простой вариант - иметь Java-класс с методом factory для устранения проблемы:
package com.beust.jcommander;
public class JCommanderFactory {
public static createWithArgs(Object cmdLineArgs) {
return new JCommander(cmdLineArgs);
}
}
В качестве альтернативы вы можете использовать http://jewelcli.sourceforge.net/usage.html. JewelCli имеет однозначный метод factory для этой же цели, а также использует технику PICA (Proxied Interfaces Configured with Annotations) http://www.devx.com/Java/Article/42492/1954. p >
На самом деле у меня есть пример использования JewelCLI с Scala здесь в переполнении стека.