tags:

views:

608

answers:

4

We have some unit tests which compile and run fine in Eclipse 3.4, but when we try to compile them using javac, it fails. I've managed to cut the code down to something small and self-contained, so it has no external dependencies. The code itself won't make much sense because it's all out of context, but that doesn't matter - I just need to find out why javac doesn't like this:

public class Test {

    public void test() {
     matchOn(someMatcher().with(anotherMatcher()));
    }

    void matchOn(SubMatcher matcher) {}

    SubMatcher someMatcher() {
        return new SubMatcher();
    }

    Matcher anotherMatcher() {
        return null;
    }
}

interface Matcher <U, T> {}

class BaseMatcher implements Matcher {
    public BaseMatcher with(Matcher<?,?> matcher) {
        return this;
    }
}

class SubMatcher extends BaseMatcher {
    @Override
    public SubMatcher with(Matcher matcher) {
     return this;
    }
}

I've tried with JDK 1.5.0_10 and 1.6.0_13, with the same result:

Test.java:6: matchOn(test.SubMatcher) in test.Test cannot be applied to (test.BaseMatcher)
                matchOn(someMatcher().with(anotherMatcher()));
                ^
1 error

I think this is perfectly valid Java. The SubMatcher.with() method returns a more specific type than BaseMatcher.with(), but the compiler seems to think that the return type is BaseMatcher. However, it's possible that the Eclipse compiler is incorrectly allowing something it shouldn't be.

Any ideas?

A: 

Check which jre or jdk you are compiling with on both Eclipse and terminal. Maybe it might be the version issue.

bLee
Eclipse is using the 1.5.0_10 JRE, the same as the javac I'm trying.
skaffman
+7  A: 

in BaseMatcher you need to specify type parameters:

public SubMatcher with(Matcher<?, ?> matcher) {

in order to allow javac to match your with method

PS

imho is a bug of eclipse compiler

dfa
Ach, I can't believe I didn't spot that....
skaffman
Yourself and Greg both got the answer, but I have to give the prize to someone, and you were slightly faster...
skaffman
A: 

Works for me:

$ java -version
openjdk version "1.7.0-internal"
OpenJDK Runtime Environment (build 1.7.0-internal-****-2009_07_23_10_21-b00)
OpenJDK 64-Bit Server VM (build 16.0-b06, mixed mode)
$ javac -XDrawDiagnostics Test.java 
$

I vaguely remember such a bugreport, but cannot give you a link to it right now.

+6  A: 

I made it build successfully by adding <?,?> to Matcher in SubMatcher.with:

class SubMatcher extends BaseMatcher {
    @Override
    public SubMatcher with(Matcher<?,?> matcher) {
        return this;
    }
}

Without this, the method signature is different from the base. I wonder whether there's a bug in the @Override checking that fails to notice this.

Greg Hewgill
This is an interesting situation. You could argue that javac is at fault here, because it's allowed the @Override annotation, but then it uses the subclass method rather than the overriden one. This is inconsistent, the annotation is there to prevent this sort of problem.The question is whether a method with a raw type parameter can override a superclass method with the same type with <?>
skaffman