あんた何言ってんの?みたいなタイトルですが、ちょっとハマったので。
Scala 2.11.6+sbt 0.13.8で試しています。
こういうJavaのインターフェースを用意して
src/main/java/org/littlewing/HasVarArgsWithGenerics.java
package org.littlewing; public interface HasVarArgsWithGenerics<T> { T method(Object... arguments); }
このインターフェースの実装を、Scalaで用意します。
src/main/scala/org/littlewings/HasVarArgsWithGenericsImpl.scala
package org.littlewings import org.littlewing.HasVarArgsWithGenerics class HasVarArgsWithGenericsImpl extends HasVarArgsWithGenerics[String] { override def method(arguments: AnyRef*): String = getClass.getSimpleName }
この状態で、Javaからこのクラスを呼び出すと
HasVarArgsWithGenerics hasVarArgs = new HasVarArgsWithGenericsImpl(); hasVarArgs.method("arg1", "arg2", "arg3");
AbstractMethodErrorになります。
java.lang.AbstractMethodError: org.littlewings.HasVarArgsWithGenericsImpl.method([Ljava/lang/Object;)Ljava/lang/Object;
どうも条件は、可変長引数を持っていること、Javaのクラスレベルで型パラメータを定義しておき、それをメソッドの戻りの型に使っていると起きそうな感じなのですが…。
メソッド宣言に型パラメータを入れただけだと、OKでした。
Scalaだと、問題なく呼べます。
val hasVarArgsWithGenerics = new HasVarArgsWithGenericsImpl hasVarArgsWithGenerics.method("arg1", "arg2", "arg3")
また、単に可変長引数を持っているだけであれば、別に問題ありません。
src/main/java/org/littlewing/HasVarArgs.java
package org.littlewing; public interface HasVarArgs { void method(Object... arguments); }
実装側。
src/main/scala/org/littlewings/HasVarArgsImpl.scala
package org.littlewings import org.littlewing.HasVarArgs class HasVarArgsImpl extends HasVarArgs { override def method(arguments: AnyRef*): Unit = () }
これであれば、JavaからもScalaからも普通に呼べます。
また、先ほどのAbstractMethodErrorになる例で、以下のようにScala側の実装クラスを直接指すと
HasVarArgsWithGenericsImpl hasVarArgs = new HasVarArgsWithGenericsImpl(); hasVarArgs.method("arg1", "arg2", "arg3");
コンパイルエラーになります。
[error] 期待値: scala.collection.Seq<java.lang.Object> [error] 検出値: java.lang.String,java.lang.String,java.lang.String [error] 理由: 実引数リストと仮引数リストの長さが異なります [error] hasVarArgs.method
まあ、ね…。
自分は、JCacheのEntryProcessorをScalaで実装して、AbstractMethodErrorが飛んできてハマったのでJavaで書き直しました。
ふーん…。