5

I have the following list defined within a Scala object:

object Foo {
    val bar = List(1, 2, 3)
}

Which seems to become a scala.collection.immutable.List<Object> when I try to use it from Java. As a consequence, I have to use getters like Foo.bar().apply$mcII$sp(i) or apply with a cast to Integer/int.

Why is the generic type Object and not Integer? This also seems to be only the case for types that exist as Java primitives; List[MyType] becomes List<MyType> in Scala.

beatngu13
  • 7,201
  • 6
  • 37
  • 66
  • 1
    @StuartLC during design time in my IDE. I just wonder why this doesn't happen with non-primitives, e.g., with `List[MyType]` which becomes `List` in Java. – beatngu13 Nov 21 '18 at 12:37

3 Answers3

2

I have experienced a somewhat similar issue with Swagger not responding well to Scala.

I don't know why, but this bug/feature is related to Java's primitives that dont't have setters and getters (like objects). Since the Java compiler can't find a suiting object, it just compiles it down to Object.

Scala collections have made converters to fix this: https://docs.scala-lang.org/overviews/collections/conversions-between-java-and-scala-collections.html

The only workaround I can think about is to use: Foo.bar.toJava

Sources: Deserializing Scala list with Jackson

https://stackoverflow.com/a/52581955/2291510

Spring RequestParam formatter for Scala.Option

Good luck!

Mr.Turtle
  • 2,950
  • 6
  • 28
  • 46
2

This happens due to the fact that Java does not support primitive types in generic types, generics are a compile time construct only in Java, they do not exist in JVM bytecode, thus they must be convertible to Java's Object type, which primitives cannot.

If we compile the code using the -Xprint:jvm flag, you can see that List[Int] actually compiles to the non generic List:

package com.yuvalitzchakov.github {
  object Foo extends Object {
    private[this] val bar: List = _;
    <stable> <accessor> def bar(): List = Foo.this.bar;
    def <init>(): com.yuvalitzchakov.github.Foo.type = {
      Foo.super.<init>();
      Foo.this.bar = scala.collection.immutable.List.apply(scala.Predef.wrapIntArray(Array[Int]{1, 2, 3}));
      ()
    }
  }
}

If Foo.bar was a List[Integer], this would yield a List<Integer> in Java, instead of List<Object>

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • Do you know why it doesn't compile to the corresponding primitive wrapper types such as `Integer`? – beatngu13 Nov 21 '18 at 16:36
  • 1
    @beatngu13 That's a good question, I actually do not know why there's no auto lifting to the wrapper types (unless we explicitly annotate `bar` with a `List[Integer]` type). – Yuval Itzchakov Nov 21 '18 at 16:49
1

Try to use collection decorator asJava:

val javabar = bar.asJava
Vladimir Berezkin
  • 3,580
  • 4
  • 27
  • 33
  • I know that this would be a workaround for the problem. I just wonder why the Scala `List[Int]` gets compiled to `List – beatngu13 Nov 21 '18 at 12:34