12
votes

Scala defines an AnyRef class which is after compilation interpreted somewhat as Java's Object class. The AnyRef class, however, is not exactly equivalent to Object from the language point of view, because it introduces several new methods, such as eq(), which takes AnyRef and returns Boolean and compares references for identity

If there is a class in Java which itself defines the eq() method with a different result type and an interface which this class implements also having this method:

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

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

then its eq method becomes inaccessible to Scala code if called via interface reference

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

The eq method Scala knows about here is the eq method from the AnyRef class being "glued" to interface I which came from Java without that method, but with an eq() method of its own with a different result type. I can explain this behavior, but can't solve the real-life task when I have to call this Java eq() method without a possiblity to modify the code of the Java third-party library. Namely I'm talking about Liferay and its Dynamic Query API and the interface named com.liferay.portal.kernel.dao.orm.Property. It has an eq() method taking Object and returning Criterion. This code won't compile in Scala:

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

because eq won't be interpreted correctly. Just to mention, the Property class has another overload of the eq() method which takes DynamicQuery as parameter. This overload is accessible from Scala.

Do you know of any way to call that eq(Object) method of Java interface from Scala?

Scala version used is 2.8.1

3
Did you try a.eq(b.asInstanceOf[Object])?Abhinav Sarkar
Works for me, no compilation error, and the correct method gets called.Lex
Unfortunately it doesn't help. I've updated the description, there's also an interface playing a role herekyrel
@Lex, sorry, fixed the question, thank you for the effortkyrel
I'm not an expert with reflection, but can you somehow get to that method this way?ziggystar

3 Answers

5
votes

Interesting problem: I hadn't seen this one before. I don't know how to solve it in Scala, or even if it is possible at all. On such situations, however, the best you can do is create a wrapper in Java. For example:

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

You then just call Eq.eq(x, y) instead of x.eq(y).

3
votes

You can do it via reflection, but I don't know if that's what you'd want since it's kind of ugly.

FWIW, you can do it by:

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

I must not be grasping everything because it seems too obvious. If (i:I).eq(o): String does not work but A.eq(o): String works, why this doesn't work?

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

So

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

(replace XYZ with whatever concrete class is instanciated such as com.liferay.portal.dao.orm.hibernate.PropertyImpl)