5

Eclipse 3.4. Java compiler level 1.6 JRE IBM 1.6

We have a library class that we cannot change that is of the form.

import java.util.Hashtable;
public class A extends Hashtable {
  ...
}

And we have build a utility class to provide easy access to A.

public class B {
  private A a;
  public B() {
    this.a = new A();
  }
  public B(final A props) {
    this.a = props;
  }
  public B(final Map<String, String> props) {
    this();
    for (String key : props.keySet()) {
      add(key, props.get(key));
    }
  }
  @SuppressWarnings("unchecked")
  public B add(final String name, final Object value) {
    a.put(name, value);
    return this;
  }
}

The problem occurs when we try to call one of the constructors from another class.

public class C {

  public void stuff() {
    A a = new A();
    B b = new B(a);//Error in javac
  }
}

Eclipse compiles this without error, and when it is compiled through ant javac and jenkins the compiler gives an error like the following.

reference to B is ambiguous, both method B(com.foo.A) in com.bar.B and method B(java.util.Map<java.lang.String,java.lang.String>) in com.bar.B match
    [javac]         B b = new B(a);

Should this error happen in javac? In my view eclipse is correct in selecting the more specific method.

mR_fr0g
  • 8,462
  • 7
  • 39
  • 54
  • 1
    Are you sure you are using the same JDK inside Eclipse as for java? – dbalakirev Sep 26 '12 at 07:46
  • 3
    A extends `HashTable`. Should that be `Hashtable`? – David Grant Sep 26 '12 at 07:49
  • 1
    It works if you remove the generics from the second constructor i.e. change it to `public B(final Map props)`. Not sure why. Sounds like a bug in `javac`. – dogbane Sep 26 '12 at 08:01
  • @dave00 can't see this information on the jenkins dashboard or build output. I will check with one of the jenkins admins. This is the first ocurence of this kind of problem after about a year of builds, so I suspect they are the same. – mR_fr0g Sep 26 '12 at 08:07
  • @dogbane Yes that is indeed the temp fix I have added to get our jenkins build working. Now to raise a bug. – mR_fr0g Sep 27 '12 at 09:05

3 Answers3

0

Since HashTable implements Map, there is ambiguity. HThis answer contains some goot insights:

Calling ambiguously overloaded constructor in Java

Community
  • 1
  • 1
Konstantin Pribluda
  • 12,329
  • 1
  • 30
  • 35
  • But Hashtable is more specific than Map so it should be selected without abiguity. JLS -> http://docs.oracle.com/javase/specs/jls/se5.0/html/expressions.html#308804 This must be a problem relating to the generics declared on the Map – mR_fr0g Sep 26 '12 at 08:46
0

The problem is that one constructor accept a raw Hashtable, while the other accept a parameterized Map. Both constructors are applicable, however the disambiguation logic doesn't work in this case, as, per Java Language Specification - a constructor would be more specfic than the other one only if its argument was a (strict) subtype of the other argument. Unchecked subtyping is not allowed during this stage, hence the ambiguity.

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
-1

As class A extends Hashtable and Hashtable itself implements Map interface, so you can say class A gets properties of Map and it also becomes Map.

When you are having public B(final A props) and public B(final Map<String, String> props) It is like you are having a map argument in both the constructors.

That's why it gives you ambiguity.

gprathour
  • 14,813
  • 5
  • 66
  • 90
  • -1 I don't think you're explaination is correct. It is perfectly valid to have overloaded methods with parameters that are sub-types of each other. As I stated in the question Eclipse is able to compile this without a problem. The compiler will pick the more specific method based on the declared type of the parameter at runtime. Since Hashtable is more specific than Map it should be selected without abiguity. JLS -> docs.oracle.com/javase/specs/jls/se5.0/html/… This must be a problem relating to the generics declared on the Map – mR_fr0g Sep 26 '12 at 12:05