1

Supposed I have a Java API like below:

public class JavaApi<T> {
    public void foo(T[] data) {
        ...
    }
}

And I'd like to call it from Scala with the following class:

class Caller[T] {
    val javaApi = new JavaApi[T]()

    def callApi(data: Array[T]) = javaApi.foo(data)
}

On compile, I get the following:

type mismatch;
found   : Array[T]
required: Array[T with Object]
Note: T >: T with Object, but class Array is invariant in type T.
You may with to investigate a wildcard type such as `_ >: T with Object`. (SLS 3.2.10)
  def callApi(data: Array[T]) = javaApi.foo(data)
Wins
  • 3,420
  • 4
  • 36
  • 70
  • 3
    Because your Scala code places no type constraint on `T`, the latter could be an `AnyVal`, which is incompatible with your Java code. Therefore, you should define your `Caller` class as `class Caller[T <: AnyRef] {...}`. – jub0bs Feb 02 '17 at 08:38
  • Thank, that clears up the compilation issue. But I thought when compiled, all classes are rooted to Object regardless whether it's scala or java class? – Wins Feb 02 '17 at 08:40
  • I don't understand what you mean by that... – jub0bs Feb 02 '17 at 08:41
  • What I'm saying is that I thought all classes eventually extending `java.lang.Object` regardless whether the class is written in Scala or Java. Doesn't it? – Wins Feb 02 '17 at 08:42

2 Answers2

1

You may review the Scala type hierarchy. More specifically the phrase:

If Scala is used in the context of a Java runtime environment, then scala.AnyRef corresponds to java.lang.Object

So, by changing it as Jubobs suggested you are sure that the type correspond to an object:

class Caller[T<: AnyRef] {
    val javaApi = new JavaApi[T]()

    def callApi(data: Array[T]) = javaApi.foo(data)
}

So if you need any value type like int, char, boolean you will need to convert them to their object equivalent boxed Java type like Integer, Character or Boolean. See: enter image description here

borjab
  • 11,149
  • 6
  • 71
  • 98
0

This is caused by Java does not support polymorphic of primitive type.

Although Scala deal anything as Object but after compiler compile, maybe it will convert object to primitive type arrays for performance, such as:

scala> var a = Array(1, 2, 3)
a: Array[Int] = Array(1, 2, 3)
scala> :javap -c a
public class $line3.$read$$iw$$iw$ {
  ...
  public int[] a();
  ...

As you can see, the above Array[Int] has been convert to int[] primitive type arrays.

so for this reason, this maybe cause incompatible for Java method.

Solution:

  1. As @Jubobs said, bound T to T <: AnyRef. as val a = Array[Integer](1, 2, 3), the compiler will deal it as Integer[] type.
  2. Use List to replace Array,List always reference type.

Reference:

https://issues.scala-lang.org/browse/SI-750

Community
  • 1
  • 1
chengpohi
  • 14,064
  • 1
  • 24
  • 42