views:

681

answers:

3

I have three java types as defined below:

Main.java:

import java.util.Arrays;
import java.util.List;

public class Main 
{
    private Object callFunction() 
    {
     OperationDefinitions func = OperationDefinitions.CONCATENATE;
     List<Object> values = Arrays.asList(new Object[] {"ABC", "-", "DEF"});
     return func.call (values);
    }

    public static void main (String[] args)
    {
     Main main = new Main(); 
     System.out.println (main.callFunction());
    }
}

Operation.java

import java.util.List;

public interface Operation
{
    abstract Object call(List<Object> params);
}

OperationDefinitions.java

import java.util.List;

enum OperationDefinitions implements Operation
{
    CONCATENATE() {
     public Object call(List<Object> params) 
     {
      StringBuilder builder = new StringBuilder();
      for (Object param : params) builder.append((String)param);
      return builder.toString();
     }
    },
    ;

}

(This is almost exactly the example given in Effective Java 2nd ed. Item 30) The code above compiles and runs just fine in eclipse, but with Sun javac I get the following error:

Main.java:12: cannot find symbol
symbol  : method call(java.util.List<java.lang.Object>)
location: class OperationDefinitions
     return func.call (values);
                           ^
1 error

If I change line 12 of Main.java from return func.call(values); to return ((Operation)func).call(values) it compiles fine. Furthermore, if I put the three types (Operation, Main and OperationDefinitions) together as three subclasses of a single main class, it compiles fine as well.

So I do have workarounds for my problem, but I do wonder, why does javac require a cast here, but eclipse doesn't? Is this a bug in javac or in eclipse?

I've tried both Sun javac 1.5.0_19 and 1.6.0_16

+3  A: 

It might be a bug in Sun's javac. func is an enum (even if that enum implements Operation) and the Enum class doesn't have a method call(). To solve the issue, I suggest to change the assignment:

Operation func = OperationDefinitions.CONCATENATE;

That will also make it clear what you expect: An operation, not an enum. The enum is just a convenient way to collect all possible operations (a container if you wish).

Aaron Digulla
+1 for style, normally that would be the right thing to do. What I haven't explained here is that this is just a small fragment of the real code, and OperationDefinitions has extra member functions that are not in Operation, like getHelp() and getDescription()
amarillion
A: 

I suspect this is actually a bug in javac; OperationDefinitions definitely does have an (abstract) method call(java.util.List), since it implements the Operation interface. And the class definition is valid, since all constants provide a concrete implementation of this interface.

One thing that might be partially responsible for this, is that to my knowledge all methods defined in an interface must be public. If you've really defined the call method in the interface with the default access modifier, I'd expect the compiler to reject it - but if it doesn't then it wouldn't surprise me to see problems down the line. If this was a typo then fine, but if it's like that in your code try declaring it as public and seeing if the problem goes away.

Andrzej Doyle
All methods in interface are implicitly abstract and public. If you omit those modifiers (which is AFAIK recommended), the compiler will add them for you. If you write any other modifier, you'll get error.
Tadeusz Kopec
+1  A: 

Could this be Bug 6522780?
Or Bug 6330385?
Or Bug 6724345 - fixed in JDK 7 - so you could test that.

Stephen Denne
It looks like this is indeed bug 6724345. Thanks!
amarillion