Abstract methods and the varargs annotation

java, scala, scala-java-interop, variadic-functions

Solution

I don't know `Scala`, but in Java varargs is just an array.

So in Java it will work this way, with one warning:

package tests.StackOverflow.q27052394;

import java.util.Arrays;

public class Runner {

    public interface Bar {
      public abstract void bar(java.lang.String ... ss);
    }

    public static class Baz implements Bar {
      public void bar(java.lang.String[] array) {
          System.out.println(Arrays.toString(array));
      }
    }

    public static void main(String[] args) {

        Bar b = new Baz();

        b.bar("hello", "world");

    }

}

May be if you can fool `Scala` the same way, you will overcome the bug.

Problem

Scala provides a `@varargs` annotation that generates a Java varargs forwarder method, which makes it possible to write something like this: ``` import scala.annotation.varargs class Foo { @varargs def foo(args: String*): Unit = { args.foreach(println) } } ``` And then to call this method from Java without needing to create a `scala.Seq`: ``` Foo foo = new Foo(); foo.foo("a", "b"); ``` Which is pretty nice. Unfortunately the forwarding part doesn't seem to happen when the method is abstract: ``` trait Bar { @varargs def bar(args: String*): Unit } class Baz extends Bar { def bar(args: String*): Unit = { args.foreach(println) } } ``` Now if we have this Java code: ``` Bar bar = new Baz(); bar.bar("a", "b"); ``` We get this exception (at runtime): ``` java.lang.AbstractMethodError: Baz.bar([Ljava/lang/String;)V ``` We can confirm the problem with `javap`: ``` public interface Bar { public abstract void bar(java.lang.String...); public abstract void bar(scala.collection.Seq<java.lang.String>); } public class Baz implements Bar { public void bar(scala.collection.Seq<java.lang.String>); public Baz(); } ``` So nope, the forwarder definitely isn't getting implemented. Putting the annotation on both `bar` methods fails to compile: ``` A method with a varargs annotation produces a forwarder method with the same signature (args: Array[String])Unit as an existing method. ``` And of course putting the annotation only on the `bar` in `Baz` means we can't use the forwarder from a `Bar` instance. This seems like it must be a bug, but it also seems extremely easy to run into, and I'm not seeing anything in the issue tracker. Am I using `@varargs` correctly? If so, is there a workaround that would make it do what you'd expect here?

Original source