@Override and interface

Jim Leary, my colleague at CloudBees, got me into digging into this.

The question is around putting the @Override annoation on a method that implements an interface method, like this:

public class Foo implements Runnable {
    public void run() {}

As you can see in the javadoc, when @Override was originally introduced, such use was not allowed. javac 1.5 rejects this, too (I verified this in 1.5.0_22.)

Sun intended to change this in 1.6. Javac 1.6 indeed changed the behaviour to allow it (verified this in 1.6.0_26), but someone forgot to update the documentation, as you can see in the Java 6 API reference.

The interesting thing is, if you use Javac 1.6 with “-source 1.5” and/or “-target 1.5”. In all the possible 3 combinations, the above code compiles. Is this a bug, or is this correct? The interesting thing is that the semantics of @Override is defined in the library, not in the Java language spec. So an argument can be made that this is as it should be — JLS, which governs the -source/-target switches, have nothing to do with this annotation. It’s akin to your code relying on newly introduced types in Java 6. If you compile them with Javac 1.6 with -source 1.5, it won’t raise an error.

But IDEs do seem to tie this with the language level. Jim said Eclipse, when set to language level 1.5, it will flag the above code as an error. I verified that IntelliJ does the same (but only in the editor, as the actual compilation happens via javac so the build will succeed.)

So the end result is ugly. If you open the project in your IDE, you see all these errors, but your build (nor test nor any actual execution, for that matter) will not catch this problem. Even if this was a bug in javac, I don’t see it getting “fixed” — the last thing you want is your security update relese to Java6 break all your builds.

I guess the right thing to do for projects (like Jenkins) is to try to avoid putting @Override on interfaces and as we discover them, remove them. So that people who open the source tree in IDE won’t see those false positive errors. This is a bummer because it’s actually useful to have @Override on interfaces (that’s why the behaviour was changed in 1.6 in the first place!) Does anyone know of a FindBugs rule or some refactoring tool to check this? Or should these be filed as bugs against IDEs? For enforcing something that’s not in JLS?

8 Comments Add yours

  1. Do you still use Firefox 0.8? Because that was the most recent version of Firefox when Java 5 was released, almost 8 years ago.

    We shouldn’t remove the @Override annotations – we should remove the Java 5 compatibility flags from our javac command line. Java 6 has been around for more than 5 years, people had enough time to update their CI servers.

  2. Jon Stevens says:

    I recently had this in one of my projects. I use Eclipse, so I just do a project specific override (setting the values as you mentioned above) and then check in the .settings/ folder which is created. Problem solved.

    That said, 1.5 is LONG past the end of life date. Time to just target 1.6 if you ask me.

  3. mirko friedenhagen says:

    Hello Koshuke, AFAIK Java 1.5 has reached EOL more than one year ago and 1.6 will reach it’s EOL this year.
    Maybe people should just upgrade their systems?


  4. kohsuke says:

    Good point about the age of Java5. I should look into the anonymous usage stats to see the percentage of users running Jenkins on Java5 vs Java6+

  5. Jim Leary says:

    Thanks for the acknowledgment, KK. As Jon mentioned above, I too just changed the project-specific settings and I was good to go.

    I wouldn’t take out the @Override annotations from the code: I would update the goals that generate the Eclipse projects for Jenkins so that they specify JavaSE-1.6, since as Henning and Mirko mentioned J2SE-1.5 is long past its prime.

    –Jim L.

  6. lo says:

    Noticed this a while back myself and actually got through most of the codebase I have at work to add all these missing annotations (on classes and interfaces overrides).

    Like Henning, I don’t think you should hold back.
    If your product supports Java 5 runtimes, then you just need to have your build produce the right deliverable, but surely your developers should not need to bother having their IDE set to this old language level.

  7. kohsuke says:

    But that’s the scenario that doesn’t work very well. As soon as I set the target release to 1.5, IDEs go back to the 1.5 language level, which flags these annotations by warnings.

  8. Maxi says:

    Great Article.

    I’m unfortunately working on a legacy project that compile with java 5 under maven and has annotations overriding interfaces within all the project, so this article was great approach to me

    Thanks, buddy.

Leave a Reply

Your email address will not be published. Required fields are marked *