Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling Java Generic Typed Method from Scala gives a Type mismatch error : Scala

This is my very first question down here, so i'll try to make it clear as far as i can. Other error: type mismatch; questions here are not related to this error.

I have this odd problem with scala/java inter-operability :

Let's suppose we have a Java class

public class JavaClass{
  public static <T> T[] toArray(Class<T> t, Collection<T> coll) {
    return null; // return null to make it simple
  }
}

And then i have another Scala class i just wanted to wrap this method in :

object ScalaClass{
  def toArray[T](t: java.lang.Class[T], coll: java.util.Collection[T]): Array[T] = {
    JavaClass.toArray[T](t, coll);
  }
}

compiling the Scala class gives me a very odd error :

error: type mismatch;

Any idea is appreciated.

EDIT 1: The full error message is

[ERROR] ScalaScala.scala:4002: error: type mismatch;
[INFO]  found   : Array[T]
[INFO]  required: Class[T]
[INFO]  JavaClass.toArray[T](t, coll);
[INFO]                      ^
like image 387
thevpc Avatar asked Dec 18 '19 13:12

thevpc


1 Answers

Welcome to SO.

This seems to compile, but I am not sure if it works with the real implementation of JavaClass, but I am pretty sure it should.

import scala.reflect.ClassTag

object ScalaClass {
  def toArray[T <: AnyRef](coll: java.util.Collection[T])(implicit ct: ClassTag[T]): Array[T] =
    JavaClass.toArray[T](ct.runtimeClass.asInstanceOf[Class[T]], coll)
}

To call it from Scala you just need to pass the java collection, it would get the correct class from the type, like this:

val col: java.util.Collection[String] = ???

val array: Array[String] = ScalaClass.toArray(col)

Edit

If you want to preserve the original signature, you have to do this:

object ScalaClass {
  def toArray[T <: AnyRef](t: java.lang.Class[T], coll: java.util.Collection[T]): Array[T] =
    JavaClass.toArray[T](t, coll)
}

Which you can use like this:

val col: java.util.Collection[String] = ???

val array: Array[String] = ScalaClass.toArray(classOf[String], col)

In both cases the trick is the <: AnyRef type bound.
IMHO, the first version is more ergonomic to be used on idiomatic Scala code.

like image 55
Luis Miguel Mejía Suárez Avatar answered Sep 23 '22 21:09

Luis Miguel Mejía Suárez