# Friday, 04 November 2011
« New Development Snapshot | Main | Java Method Overriding Is FUBAR Part 2 o... »
Java Method Overriding Is FUBAR Part 1 of ∞

The Java Virtual Machine Specification Java SE 7 Edition finally has a section about method overriding (5.4.5). Unfortunately, it does not document the behavior of the Java 7 reference implementation, nor the Java 6 behavior. It also turns out to be a bad design.

Suppose you have a third party widget framework that has a class:

package org.example;

public class Widget

And your application has a subclass of Widget:

package fubar.tech;

public class MyWidget extends org.example.Widget
  void frob() { ... }

The frob() method is package private and you don't want external code calling it. Now a new version of the widget framework is released that adds a frob method to Widget:

package org.example;

public class Widget
  public void frob() { }

Starting with Java 7 (and this particular behavior is defined by the spec) your package private MyWidget frob() will now override Widget.frob() and hence be callable by anyone who happens to have a reference to your object. If MyWidget.frob() does anything security critical, the third party framework has now introduced a vulnerability in your code.

Java already had a poor story for adding virtual methods to public classes, but this change has made it even worse.

Friday, 04 November 2011 07:01:39 (W. Europe Standard Time, UTC+01:00)  #    Comments [7]
Friday, 04 November 2011 18:34:30 (W. Europe Standard Time, UTC+01:00)
Would your criticism be satisfied If the compiler were changed to

(1) Mangle all method names and fields with the visibility level
(2) When an override raises visibility, add a forwarding method
(3) Possibly add unmangled forwarding methods for public methods only for backwards compatibility with older class file versions.

For example, (and ignoring identifier hygiene for simplicity), when the java source file below is compiled:

class C {
void foo() {}
protected void bar() {}

class D extends C {
public foo() {}
@Override public bar() {}

the .class file for C would define

package$foo() // mangled per (1)

and the .class file for D would define

// synthetic forwarder
void protected$bar() { public$bar(); } // per (2)
void foo() { public$foo(); } // per (3)
void bar() { public$bar(); } // per (3)

Static methods would not change, so there would be no need to change how main is located. Class.getMethod and friends would need to change to prefer the most-visible version, but would not change in API.
Mike Samuel
Friday, 04 November 2011 21:21:27 (W. Europe Standard Time, UTC+01:00)
I just tried your exact example on my machine with Java 7, and the compiler generated the following error message:

Cannot reduce the visibility of the inherited method from Widget

So I'm confused. Did you try this yourself and get a different result?
Friday, 04 November 2011 22:37:02 (W. Europe Standard Time, UTC+01:00)
Confirmed above, OpenJDK7b147 produces a compile time error.
Friday, 04 November 2011 22:43:29 (W. Europe Standard Time, UTC+01:00)
I would expect an IncompatibleClassChangeError in this case. What IKVM do in this case?
Friday, 04 November 2011 23:32:42 (W. Europe Standard Time, UTC+01:00)
Guys, I'm a JVM developer I don't care about the javac compiler only about the runtime. It doesn't matter one bit what javac does, situations like this can and do arise in real life and need to be (better) supported by the VM.
Friday, 04 November 2011 23:35:07 (W. Europe Standard Time, UTC+01:00)
@Volker After I check in my current changes IKVM will do the same as HotSpot (apart from the exception described in part 5).
Friday, 04 November 2011 23:37:44 (W. Europe Standard Time, UTC+01:00)
@Mike Samuel It would be possible to add a lot of hacks to work around some of these issues, but the main point of these posts is to question what Oracle have been doing, because the Java 6 behavior, while certainly not perfect, was a lot less broken than the new behavior.
Home page

I apologize for the lameness of this, but the comment spam was driving me nuts. In order to be able to post a comment, you need to answer a simple question. Hopefully this question is easy enough not to annoy serious commenters, but hard enough to keep the spammers away.

Anti-Spam Question: What method on java.lang.System returns an object's original hashcode (i.e. the one that would be returned by java.lang.Object.hashCode() if it wasn't overridden)? (case is significant)

Comment (HTML not allowed)  

Live Comment Preview