Как создать новый экземпляр класса Scala с контекстом, связанным с помощью отражения Java, используя конструктор только с нулевым аргументом? - PullRequest
4 голосов
/ 19 августа 2011

Я пишу клиентский код в Scala, который должен взаимодействовать с фреймворком на Java.Фреймворк отвечает за создание экземпляров объектов классов, указанных через API, что он делает с помощью отражения.Например:

public class ReflectionUtil {

  public static <T> T newInstance(Class<T> aClass) {
    T result;
    try {
      Constructor<T> meth = aClass.getDeclaredConstructor(new Class[]{});
      meth.setAccessible(true);
      result = meth.newInstance();
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
    return result;
  }
}

Классы экземпляров объектов, которые я хочу создать, реализованы в Scala и имеют параметризацию для типа, к которому привязан контекст.Например:

class OrderedValue[A](var value: A)(implicit ord: Ordering[A]) {
  def get: A = value
  def set(x: A) = { value = x }
  def cmp(that: OrderedValue[A]): Int = ord.compare(this.value, that.value)
}

Я сталкиваюсь с проблемой, когда передаю этот класс в среду Java для создания новых экземпляров, поскольку среда предполагает, что класс будет иметь конструктор с нулевым аргументом.Например, следующий код приведет к NoSuchMethodException из newInstance:

def main(args: Array[String]) {

  val a: OrderedValue[Int] = ReflectionUtil.newInstance(classOf[OrderedValue[Int]])
  val b: OrderedValue[Int] = ReflectionUtil.newInstance(classOf[OrderedValue[Int]])

  a.set(3)
  b.set(5)

  println(a.cmp(b))
}

Попытка решить эту проблему - добавить конструктор с нулевым аргументом в OrderedValue, однако нетразумное значение для неявного параметра ord.Установка null приведет к NullPointerException в cmp:

def this() = this(null.asInstanceOf[A])(null.asInstanceOf[Ordering[A]])

Другой подход заключается в создании подкласса конкретного конкретного значения OrderedValue.Например:

class OrderedIntValue(val v: Int) extends OrderedValue[Int](v) {
  def this() = this(null.asInstanceOf[Int])
}

val a: OrderedValue[Int] = ReflectionUtil.newInstance(classOf[OrderedValue[Int]])

Это будет работать, но не идеально, так как не всегда удобно или возможно узнать конкретный тип OrderedValue.Например, newInstance может вызываться в области видимости, которая также параметризована для типа (т. Е. Мы не знаем, что это конкретно Int).

Поэтому мой вопрос: учитывая границы этого контекста(т. е. классы типов) являются очень полезной и в настоящее время широко используемой функцией в Scala, и, учитывая, что я не могу изменить внутреннюю среду Java-фреймворка, с которым я взаимодействую, сталкивался ли кто-либо с разработанным подходом, который может заставить все это работать

Ответы [ 2 ]

7 голосов
/ 19 августа 2011

Неявные аргументы заполняются компилятором Scala во время компиляции.Если вы хотите создавать экземпляры классов, используя отражение, вам придется указать эти аргументы вручную.Обойти это просто невозможно.Таким образом, вы можете иметь контекстные границы или конструкторы без аргументов.

3 голосов
/ 19 августа 2011

Я обнаружил, что самый простой способ вызова кода Scala из Java - это написать промежуточный слой Scala с эквивалентом POJO для Scala.Никаких последствий, никаких замыканий в подписях, никаких объектов Companion, никаких сложных выводов типов и т. Д. (Конечно, вы можете использовать их внутри).Я также пытаюсь заменить большинство типов коллекций scala в сигнатурах на java.util Collections.

Да, это уродливо, утомительно и не очень гибко, но, по крайней мере, устраняет кошмар синтаксиса со стороны Java.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...