Implementing unsafe Java interfaces
-
20-09-2019 - |
Question
I've ran into a problem recently while developing with Spring Security. It has an interface GrantedAuthority
with following signature:
public interface GrantedAuthority extends Serializable, Comparable
And as for Java 1.5 and later, the interface Comparable
takes a type parameter T
, which is omitted in Spring Security libraries (obviously, for JVM 1.4 compatibility).
So I am trying to implement GrantedAuthority
in Scala.
class Role extends GrantedAuthority {
. . .
def compareTo(obj: Any): Int = obj match {
case (r: Role) => r.toString.compareTo(this.toString)
case _ => -1
}
}
It does not compile:
error: class Role needs to be abstract, since method compareTo in trait Comparable of type (T)Int is not defined
How can I implement such interface in Scala?
Solution
Interop problems with Java Generics come in (at least) two forms:
- Java code that omits type arguments, as in your example, leads to 'raw types'.
Comparable
is treated as the existential typeComparable[_]
. Sometimes you can cast your way out of this problem. However, I don't see a way to implementdef compareTo(other: _) = ...
in this case. - Java generics don't have a notion of declaration site variance. To extend
Comparable[T]
with a contravariant scala traitOrdering[-T]
an error would occur unless you use the@uncheckedVariance
annotation. (Discussion on the mailing list)
I suggest you try to upgrade to Spring 3.x which is compiled against Java 1.5. If this is not possible, write a base class BaseGrantedAuthority
in Java that implements compareTo
and delegates to a template method that can implemented in Scala.