calling java varargs from scala with overloading

2019-08-15 08:59发布

问题:

It's another question about scala-java compatibility related to varargs feature. The key difference is that java's part is overloaded.

It resembles this scala code:

object Test {
  def test( xa : String* ) = print( xa.mkString(",") )
  def test( xs : Seq[String] ) = print( xs.mkString(",") )
}

Scala unlike java mark such overloading as invalid

error: double definition:
def test(xa: String*): Unit at line 11 and
def test(xs: Seq[String]): Unit at line 12
have same type after erasure: (xa: Seq)Unit
         def test( xs : Seq[String] ) = print( xs.mkString(",") )
             ^

But java agrees to compile similar construction.

That surprises scala and it produces an error trying to invoke appropriate java method. The scala compiler left "no `: _*' annotation allowed here (such annotations are only allowed in arguments to *-parameters)" message

How to properly invoke varargs method under such conditions?


I've found corresponding bug in the scala issues tracker

回答1:

I have run into a similar problem when extending some Java interfaces.

Specifically, org.hibernate.Session has these two virtual methods:

ProcedureCall createStoredProcedureCall(String var1, Class... var2);

ProcedureCall createStoredProcedureCall(String var1, String... var2);

And, as you experienced, Scala gives an error if you try and implement them directly in a Scala class. At this time, the only work around that I know of is to create a "bridge" class in Java that implements the two methods and passes their calls to two new virtual functions that do not have overloaded naming. (see example below)

For the example case given in the question, since overloading will not be possible, it would be necessary to give the two functions distinct names. It is, unfortunately, the only solution that will work at this time.

@Override
public ProcedureCall createStoredProcedureCall(String procedureName, Class... resultClasses) {
    return createStoredProcedureCall0(procedureName, resultClasses);
}

abstract ProcedureCall createStoredProcedureCall0(String procedureName, Class... resultClasses);

@Override
public ProcedureCall createStoredProcedureCall(String procedureName, String... resultSetMappings) {
    return createStoredProcedureCall1(procedureName, resultSetMappings);
}

abstract public ProcedureCall createStoredProcedureCall1(String procedureName, String... resultSetMappings);