Как вызвать метод 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
Ответы
Ответ 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
)