JDK-8022162 : Incorrect signature determination for certain inner class generics
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 6u37,8
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: linux
  • Submitted: 2013-03-20
  • Updated: 2014-02-03
  • Resolved: 2013-09-02
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8
8 b108Fixed
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
[pawel@druid]~/jprogs/crazy$ /opt/java/jdk1.6.0_37/bin/java -version
java version  " 1.6.0_37 " 
Java(TM) SE Runtime Environment (build 1.6.0_37-b06)
Java HotSpot(TM) Server VM (build 20.12-b01, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Oracle Linux 6
[pawel@druid]~/jprogs/crazy$ uname -a
Linux druid.goldspot.lan 2.6.39-200.34.1.el6uek.x86_64 #1 SMP Thu Oct 18 17:00:17 PDT 2012 x86_64 x86_64 x86_64 GNU/Linux


A DESCRIPTION OF THE PROBLEM :
Compiler improperly determines method signature when loading class files, if generics are used for inner classes.

I can't say that I know exactly what breaks, but the source code in the  " SOURCE CODE "  section gives a sufficient test case.

A class has a method with signature   'void doSomething(Inner1.Inner2 arg)', which is used from a class that extends the first class. However, compiler treats the signature as 'void soSomething(Inner2 arg)' instead.

Note, that this *only* happens when compiler loads existing classes, and does not happen when compiler has all classes as sources to compile from.

This works:
[pawel@druid]~/jprogs/crazy$ /opt/java/jdk1.6.0_37/bin/javac -verbose p[123]/*.java

This results in an error:
[pawel@druid]~/jprogs/crazy$ find . -name \*.class | xargs rm
[pawel@druid]~/jprogs/crazy$ for i in 1 2 3 ; do /opt/java/jdk1.6.0_37/bin/javac -cp . p$i/*.java ; done
p3/High.java:7: doSomething(p2.QueueRunner<p3.High.MyItem>.Element) in p2.QueueRunner<p3.High.MyItem> cannot be applied to (p2.QueueRunner<p3.High.MyItem>.MyDLL.Element)
            doSomething(item);
            ^
1 error



EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Compilation should be successful in both cases
ACTUAL -
Compilation is not successful when used classes are loaded from .class files

ERROR MESSAGES/STACK TRACES THAT OCCUR :
[pawel@druid]~/jprogs/crazy$ /opt/java/jdk1.6.0_37/bin/javac -cp . p3/High.java
p3/High.java:13: doSomething(p2.QueueRunner<p3.High.MyItem>.Element) in p2.QueueRunner<p3.High.MyItem> cannot be applied to (p2.QueueRunner<p3.High.MyItem>.MyDLL.Element)
            doSomething(item);
            ^
1 error


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------

Source code is spread across 3 package directories: p1, p2 and p3.

[pawel@druid]~/jprogs/crazy$ cat p1/DLL.java
package p1;
public class DLL<T> {
    public class Element {
        T object;
    }
}

[pawel@druid]~/jprogs/crazy$ cat p2/QueueRunner.java
package p2;
import p1.*;
public abstract class QueueRunner<T> {
    protected void doSomething(MyDLL.Element e) {}
    public class MyDLL extends DLL<T> {
        public class Element extends DLL<T>.Element {}
    }
}

[pawel@druid]~/jprogs/crazy$ cat p3/High.java
package p3;
import p2.*;
public class High {
    static class MyItem {}
    static class EQueue extends QueueRunner<MyItem> {
        private void myMethod(MyDLL.Element item) {
            doSomething(item);
        }
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
all involved classes must be compiled in a single javac execution.
This workaround is not easy to implement in modular applications.
Comments
under review
30-08-2013

A minimal test case: p1/DLL.java package p1; public class DLL<T> { } abstract class QueueRunner<T> { protected void doSomething(MyDLL.Element e) {} public class MyDLL extends DLL<T> { public class Element {} } } p1/High.java package p1; public class High { static class EQueue extends QueueRunner<Object> { private void myMethod(MyDLL.Element item) { doSomething(item); } } } to reproduce the error: ~/jdkVersions/jdk1.8.0/bin/javac -d classes p1/DLL.java ~/jdkVersions/jdk1.8.0/bin/javac -d classes -cp classes p1/High.java
19-08-2013

javac -d classes p1\DLL.java p2/QueueRunner.java javac -d classes -cp .\classes p2\High.java p3\High.java:7: error: incompatible types: QueueRunner<MyItem>.MyDLL.Element cannot be converted to QueueRunner<MyItem>.Element doSomething(item); ^ Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output 1 error or with -XDrawDiagnostics High.java:7:13: compiler.err.cant.apply.symbol: kindname.method, doSomething, p2.QueueRunner<p3.High.MyItem>.Element, p2.QueueRunner<p3.High.MyItem>.MyDLL.Element, kindna me.class, p2.QueueRunner<T>, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: p2.QueueRunner<p3.High.MyItem>.MyDLL.Element, p2.QueueRun ner<p3.High.MyItem>.Element)) 1 error
02-08-2013