How do I extend Java interface containing generic methods in Scala?
-
16-09-2019 - |
Question
Suppose we have the following Java interface:
// Java
public interface Foo {
<T> T bar(Class<T> c);
}
How should I extend it in Scala? Writing
// Scala
class FooString extends Foo {
override def bar(c: Class[String]): String = "hello, world";
}
will cause the compiler to throw "class FooString needs to be abstract, since method bar in trait Foo of type [T]
(Class[T])T is not defined."
Thanks in advance!
Update: The ugly truth is: I've misunderstood generics in Java.
In any case, the solutions to my woes are shown in both Nicolas' and Walter's answers, although I prefer Walter's answer better 'cos it's less verbose.
Solution
This works:
class FooString extends Foo {
def bar[String](c: Class[String]): String = "hello world".asInstanceOf[String]
}
val fs = new FooString
println(fs.bar(classOf[String]))
Edited:
The comments from @Eastsun is correct. Since bar is a generic method with type parameter T, the implementation of bar in Scala has to be a generic method as well. I think the right way to implement Foo in Scala is the following:
class FooString extends Foo {
def bar[T](c: Class[T]): T = c.newInstance.asInstanceOf[T] // c gotta have a default constructor
}
val fs = new FooString
println(fs.bar(classOf[String]).getClass) // prints "class java.lang.String"
println(fs.bar(classOf[java.util.Date]).getClass) // prints "class java.util.Date"
OTHER TIPS
It does not work because you do not implements the interface properly. The siganture of your method n scala must be:
def bar[T](c:Class[T]):T
You can fix the behaviour for String only if you want ton implements Foo.
Third try, according to our discussion:
def bar[T](c:Class[T]):T = {
// Some stuff
val o:Any = myUntypedFunction(env)
c.cast(o)
}
According to the context the myUntypedFunction will create an object, and then you use the class parameter to cast your result and obtain a T object. Once again: this behavior is the same in java and in scala.
You may change like this:
public interface Foo<T> {
T bar(Class<T> c);
}
class FooString extends Foo[String] {
override def bar(c: Class[String]): String = "hello, world";
}