JDK-8050472 : javac could generate more accurate signatures for local classes
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8u20,8u25,9
  • Priority: P5
  • Status: Closed
  • Resolution: Not an Issue
  • OS: generic
  • CPU: generic
  • Submitted: 2014-07-15
  • Updated: 2014-08-18
  • Resolved: 2014-08-18
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 9
9Resolved
Related Reports
Relates :  
Relates :  
Description
The fix for 8037934 violates the specification.

According to specification, "A class type signature must be formulated such that it can be reliably mapped to the binary name of the class it denotes by erasing any type arguments and converting each . character to a $ character.", correct class signature for inner class must be with dots "Lfoo/Foo.1Local1;".

To reproduce use code in the bug JDK-8037934.

Comments
I am happy for javac to continue generating signatures with $ characters, and no type arguments, where either a) raw classes are involved or b) local classes are ultimately enclosed by a generic class.
18-08-2014

I don't think Core Reflection expects inner class to specify type-arguments for the outer class. But it does expect that, if a signature mention a class type C which is generic, then C should be followed by a type parameter section containing all type-arguments between angular brackets. The problem in the original bug was that the class Local was nested inside a generic class - hence javac was generating Foo.Local - which violates the above rule: Foo is generic - yet it does not have any associate type parameter section. By turning it into Foo$Local - the reference to Foo is gone and the issues is worked around. There's only a single 'identifier' now that is non-generic and that is reflected in the signature attribute. I believe that the type-argument info for the enclosing class is recovered using the EnclosingMethod attribute.
16-07-2014

If Core Reflection expects (on pain of GenericSignatureFormatError) that the signature of Inner (which is nested in Outer<...>) indeed has type arguments for Outer, then there's a bug in javac, since it's generating a signature without the type arguments. That is the bug which should be fixed.
16-07-2014

I've created a spec bug to request a little clarification in the wording, but, ultimately, the fix for JDK-8050472 generates correct signatures.
16-07-2014

(Note that my section numbers are drawn from JVMS 7; in JVMS 8, the same content appears in 4.7.9.)
16-07-2014

It is true that, in general, the signature attribute (JVMS 4.3.4) is encoded with "Identifiers" delimited by '.' (plus any type arguments enclosed in '<...>' before each '.'). However, the interpretation of the "Identifier" is rather vague. It does not violate 4.3.4 to include '$' characters in the Identifier, and it is still true that, after discarding '<...>'s and replacing any '.' symbols with '$', you end up with a binary name for a class. Longstanding behavior is as follows: - Inner classes of parameterized class types are encoded with, e.g., 'LOuter<TT;>.Inner;' - Inner classes of non-generic classes are encoded with, e.g., 'LOuter$Inner;' - Inner classes of raw class types are encoded with, e.g., 'LOuter$Inner;' - Inner classes multiple levels deep may mix delimiters, e.g. 'LA$B<TT;>.C.D;' JVMS 4.3.4 limits its rules about correctness to syntax; but, to some extent, it endorses the semantic checks performed by java.lang.reflect. In the Oracle JDK, this includes that every class mentioned before a '.' symbol has the correct number of type arguments. Hence, the GenericSignatureFormatError prompting JDK-8037934, which complains that, where Outer is generic, 'LOuter.Inner;' is not well-formed (the type arguments are missing). Local and anonymous classes, the use case of JDK-8037934, are a special problem because they don't really have an enclosing class. The javac code quoted in the JDK-8037934 bug report shows that the established behavior here is to treat the outer class as if it were raw -- as noted above, 'LOuter$Inner;' is the usual encoding for a raw inner class.
16-07-2014

See Alex's comment in : JDK-8037934 This bug is wrong to claim that "Lfoo/Foo.1Local1;" should be "Lfoo/Foo$1Local1;" in a Signature attribute. $ has never been allowed in a Signature attribute. Signatures are not descriptors. See JVMS8 4.7.9.1 "Signatures" (formerly JVMS7 4.3.4). If javac has been changed to emit $ rather than . then it should be changed back. There may be bugs in the Signature parsing code w.r.t. nested types, but that is a separate issue.
16-07-2014

@Paul, I think that you worked on the related issue
16-07-2014