Description
See this [http://scala-programming-language.1934581.n4.nabble.com/valid-code-throws-NoSuchMethodError-at-runtime-td2222685.html#a2222685 thread]
Compiling this with scalac (tested 2.8.0.RC2):
abstract class BulkSearch {
type R <: Row
type Rel <: Relation [R]
type Corr <: Correspondence[R]
def searchFor(input: Rel): Mapping[Corr] = null
}
object BulkSearchInstance extends BulkSearch {
type R = UpRow
type Rel = UpRelation
type Corr = UpCorrespondence
}
class Row
class UpRow extends Row
class Relation [R <: Row]
class UpRelation extends Relation [UpRow]
class Correspondence [R <: Row]
class UpCorrespondence extends Correspondence [UpRow]
class Mapping[MC <: Correspondence[_]]
and compiling this with javac:
public class JavaApp {
public static void main(String[] args) {
BulkSearchInstance.searchFor(new UpRelation());
}
}
produces no compile-time errors but a runtime error later on:
Exception in thread "main" java.lang.NoSuchMethodError: bugs.BulkSearchInstance.searchFor(Lbugs/UpRelation;)Lbugs/Mapping;
at bugs.JavaApp.main(JavaApp.java:15)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:110)
After some analysis, I found out that is probably due to an inconsistent generic signature being generated for the static method delegate in BulkSearchInstance.class
.
Scalac generates these signatures for BulkSearchInstance.searchFor
:
method_info.descriptor (see � 4.3 JVM spec): (LRelation;)LMapping;
attribute 'Signature' (see JSR 014): (LUpRelation;)LMapping<LUpCorrespondence;>;
When javac sees that, it produces something strange (i.e. not matching the descriptor found in BulkSearchInstance.class
):
invokestatic SI-4; //Method BulkSearchInstance.searchFor:(LUpRelation;)LMapping;
which looks like the erasure of the generic signature. However, JVM's linker looks for the exact descriptor when looking for methods. I think the solution should be
- Always generate consistent descriptor and generic signature
- At least, in the case of the static delegator method in the object class, generate the most specific type possible. The method can't be overridden anyways.
Workaround: use a trait instead of an abstract class