Подтвердить что ты не робот

Как вызвать метод T eq (Object) интерфейса Java из Scala?

Scala определяет класс AnyRef, который после компиляции интерпретируется как класс Java Object. Однако класс AnyRef не является точно эквивалентным Object с точки зрения языка, поскольку он вводит несколько новых методов, таких как eq(), который принимает AnyRef и возвращает Boolean и сравнивает ссылки для идентификации

Если в Java существует класс, который сам определяет метод eq() с другим типом результата и интерфейсом, который этот класс реализует также, имея этот метод:

public interface I {
    String eq(Object that);
}

public class A implements I {
    public String eq(Object that) {return "";}
}

то его метод eq становится недоступным для кода Scala, если он вызван через ссылку на интерфейс

val i: I = new A
val a = new A
val b = Some(1)           //whatever actually
val s1: String = a.eq(b)   //compiles OK
val s2: String = i.eq(b)   //compilation error

Метод eq Scala знает здесь метод eq из класса AnyRef, который "склеивается" с интерфейсом I, который поступает из Java без этого метода, но с собственным методом eq() с другим типом результата, Я могу объяснить это поведение, но не могу решить реальную задачу, когда мне приходится называть этот метод Java eq() без возможности изменить код сторонней библиотеки Java. А именно, я говорю о Liferay и его Dynamic Query API и интерфейсе com.liferay.portal.kernel.dao.orm.Property. Он имеет метод eq(), принимающий объект и возвращающий критерий. Этот код не будет компилироваться в Scala:

val query = DynamicQueryFactoryUtil.forClass(classOf[BookmarksEntry])
.add(PropertyFactoryUtil.forName("folderId").eq(new Long(folderId)))

потому что eq не будет интерпретироваться правильно. Просто отметим, что класс Property имеет другую перегрузку метода eq(), который принимает DynamicQuery в качестве параметра. Эта перегрузка доступна из Scala.

Знаете ли вы, что любой способ вызвать этот метод eq (Object) интерфейса Java из Scala?

Scala используется версия 2.8.1

4b9b3361

Ответ 1

Интересная проблема: я раньше этого не видел. Я не знаю, как его решить в Scala, или даже если это возможно вообще. Однако в таких ситуациях лучше всего создать оболочку на Java. Например:

public class Eq {
    static public String eq(I obj, Object that) {
        return obj.eq(that);
}

Затем вы просто вызываете Eq.eq(x, y) вместо x.eq(y).

Ответ 2

Вы можете сделать это с помощью отражения, но я не знаю, что бы вы хотели, потому что это было некрасиво.

FWIW, вы можете сделать это:

i.getClass().getMethod("eq", classOf[Object]).invoke(i, "a").asInstanceOf[String]

Ответ 3

Я не должен воспринимать все, потому что это кажется слишком очевидным. Если (i:I).eq(o): String не работает, но A.eq(o): String работает, почему это не работает?

scala> i.asInstanceOf[A].eq(b)
res2: java.lang.String = str

Итак,

val query = DynamicQueryFactoryUtil.forClass(classOf[BookmarksEntry])
  .add(PropertyFactoryUtil.forName("folderId").asInstanceOf[XYZ]
  .eq(new Long(folderId)))

(замените XYZ каким-либо конкретным классом, например, com.liferay.portal.dao.orm.hibernate.PropertyImpl)