JDK-6533652 : javac allows to override a final method with a bridge
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 7
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2007-03-12
  • Updated: 2011-01-14
  • Resolved: 2011-01-14
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 7
7Resolved
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.7.0-ea"
Java(TM) SE Runtime Environment (build 1.7.0-ea-b06)
Java HotSpot(TM) Client VM (build 1.7.0-ea-b06, mixed mode, sharing)

java version "1.6.0_01"
Java(TM) SE Runtime Environment (build 1.6.0_01-b05)
Java HotSpot(TM) Server VM (build 1.6.0_01-b05, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
When a bridge is created, javac doesn't check if there is no final method that the bridge will override.

The compiler should emit an error because there is no way to create the bridge method.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
compile the code and run it.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The code should not compile.
ACTUAL -
It compiles and raises a verify error at runtime.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.VerifyError: class BridgeMyWorld$Oups overrides final method compareTo.(Ljava/lang/Object;)I
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(Unknown Source)
        at java.security.SecureClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.access$000(Unknown Source)
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClassInternal(Unknown Source)
        at BridgeMyWorld.main(BridgeMyWorld.java:15)

REPRODUCIBILITY :
This bug can be reproduced always.

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

public class BridgeMyWorld {
    public final int compareTo(Object o) {
      return 0;
    }
    
    static class Oups extends BridgeMyWorld implements Comparable<Oups> {
        public int compareTo(Oups o) {
          return 0;
        }
    }
    
    
    public static void main(String[] args) {
        Oups oups=new Oups();
        
    }
}

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

Comments
EVALUATION I think there's still a problem here - looking at the following example: class A { final void m(Object i) {} //final is not really relevant here - Object is } interface B<X> { void m(X x); } class C extends A implements B<Integer> { public void m(Integer i) {} } Does the JLS forbid this particular example? The only section that applies here is this (8.4.8.3): "It is a compile time error if a type declaration T has a member method m1 and there exists a method m2 declared in T or a supertype of T such that all of the following conditions hold: 1) m1 and m2 have the same name. 2) m2 is accessible from T. 3) The signature of m1 is not a subsignature (��8.4.2) of the signature of m2. 4) m1 or some method m1 overrides (directly or indirectly) has the same erasure as m2 or some method m2 overrides (directly or indirectly)." In this case: m1 == A.m(Object) m2 == C.m(Integer) so that: 1) m1 and m2 have the same name ('m') - satisfied 2) they are both accessible from C - satisfied 3) m1 is not a subsigature of m2 nor viceversa (one accepting Object, other accepting Integer) - satisfied 4) this is the tricky bit: this condition can be read both ways. On the one hand one could claim that there exist a method m3 == B.m(X), overridden by m2 == C.m(Integer) such that erasures of m3 and m1 are the same (m(Object)). On the other hand one could say that m3 == B.m(Integer), which means no problem, as m3's erasure would be different w.r.t. m1's. Eclipse seems to be applying the first reading, javac the second.
10-11-2010

EVALUATION ExtTest.m attempts to override Test.m but 8.4.3.3 makes that an error. So a subclass of Test cannot implement interface Foo, just like a subclass S of BridgeMyWorld cannot implement Comparable<S>. Could use some more info on what's not exactly clear.
09-11-2010

EVALUATION The following example - generics free - doesn't compile: class Test { final void m() {} } interface Foo { void m(); } class ExtTest extends Test implements Foo { public void m() {} //overriden method is final } So the original example should not compile either. Eclipse rejects both programs. yet, JLS (more specifically 8.4.8) is not crystal clear about final methods. Reassigning to spec for further evaluation.
09-11-2010