7

there are 2 methods:

public static TermsQueryBuilder termsQuery(String name, int... values) {
    return new TermsQueryBuilder(name, values);
}
public static TermsQueryBuilder termsQuery(String name, Object... values) {
    return new TermsQueryBuilder(name, values);
}

when i called

termsQuery("operatorType", 1);

it says that is ambiguous.

Please Help ...

all the methods are in Elasticsearch,for example:

public static TermsQueryBuilder termsQuery(String name, String... values) {
    return new TermsQueryBuilder(name, values);
}
public static TermsQueryBuilder termsQuery(String name, int... values) {
    return new TermsQueryBuilder(name, values);
}
public static TermsQueryBuilder termsQuery(String name, long... values) {
    return new TermsQueryBuilder(name, values);
}
...
public static TermsQueryBuilder termsQuery(String name, Object... values) {
    return new TermsQueryBuilder(name, values);
}

when I called termsQuery("operationType","1"), not ambiguous.

when I called termsQuery("operationType",1), ambiguous.

when I called termsQuery("operationType",Arrays.asList(searchParam.getOperatorType()), not ambiguous.

puzzled.....

Vic
  • 99
  • 1
  • 7
  • this java notation is to make the method accept a variable amount of (in this case) int parameter. To handle this variable amount of variables you can access it like an array. – Fady Saad Aug 06 '17 at 04:41
  • 4
    You should never use `Object` as varargs; this is the worst example. – Am_I_Helpful Aug 06 '17 at 04:42
  • 1
    Surely the constructors being called are also ambiguous? – user207421 Aug 06 '17 at 04:49
  • 1
    That's a great point, @EJP. I wonder how one would force [TermsQueryBuilder(String, int...)](http://xbib.org/elasticsearch/2.1.1/apidocs/org/elasticsearch/index/query/TermsQueryBuilder.html#TermsQueryBuilder-java.lang.String-int...-) to be called, when [TermsQueryBuilder(String, Object...)](http://xbib.org/elasticsearch/2.1.1/apidocs/org/elasticsearch/index/query/TermsQueryBuilder.html#TermsQueryBuilder-java.lang.String-java.lang.Object...-) also exists. – Ray Toal Aug 06 '17 at 05:00
  • I clarified my answer to try to say in very few words why the String version is not ambiguous but the int version is. To reduce your puzzlement, perhaps check out [this StackOverflow answer](https://stackoverflow.com/questions/14053596/compiler-error-reference-to-call-ambiguous) which references the parts of the JLS dealing with method overloading. Hope that helps. – Ray Toal Aug 06 '17 at 05:14
  • All constructors using `...` are not callable directly because for all of those `Object...` is ambiguous. Compiler error message clearly states that. – Axel Richter Aug 06 '17 at 05:20
  • @EJP The constructors are being called with arrays from the builders so they are not ambiguous. – Oleg Aug 06 '17 at 08:37
  • I was able to make it work by casting the value to object before sending it – Martin Blaustein Feb 26 '18 at 16:19

3 Answers3

3

All constructors using varargs <any primitive>... are not callable directly using comma separated list of primitives if Object... exists because for all of those Object... is ambiguous. Compiler error message clearly states that.

We could call them using arrays:

termsQuery("operatorType", new int[]{1, 2, 3}).

TermsQueryBuilder termsQuery(String name, Object... values) and TermsQueryBuilder termsQuery(String name, String... values) are not ambiguous because while String is also an Object it is a more special object than just Object.

The following code works and should show what happens exactly:

public class TestAmbiguous {

 public static TermsQueryBuilder termsQuery(String name, int... values) {
    return new TermsQueryBuilder(name, values);
 }
 public static TermsQueryBuilder termsQuery(String name, double... values) {
    return new TermsQueryBuilder(name, values);
 }
 public static TermsQueryBuilder termsQuery(String name, Object... values) {
    return new TermsQueryBuilder(name, values);
 }
 public static TermsQueryBuilder termsQuery(String name, String... values) {
    return new TermsQueryBuilder(name, values);
 }

 public static void main(String[] args) {
  TermsQueryBuilder builder;
  builder = termsQuery("operatorType", 1, 1.0, 1.0f, "test", new Integer(1), new Double(1), new Float(1), new String("test"));
  builder = termsQuery("operatorType", "test", new String("test"));
  builder = termsQuery("operatorType", new int[]{1, 2, 3});
  builder = termsQuery("operatorType", new double[]{1, 2, 3});
  builder = termsQuery("operatorType", new float[]{1, 2, 3});
  builder = termsQuery("operatorType", (Object[]) new Float[]{1f, 2f, 3f});
 }
}

class TermsQueryBuilder {
 TermsQueryBuilder(String name, int... values) {
  System.out.println("_____________________________________");
  System.out.println("primitive int");
  for (int i = 0 ; i < values.length; i++) {
   System.out.println(values[i]);
  }
 }
 TermsQueryBuilder(String name, double... values) {
  System.out.println("_____________________________________");
  System.out.println("primitive double");
  for (int i = 0 ; i < values.length; i++) {
   System.out.println(values[i]);
  }
 }
 TermsQueryBuilder(String name, Object... values) {
  System.out.println("_____________________________________");
  System.out.println("Any objects");
  for (int i = 0 ; i < values.length; i++) {
   System.out.println(values[i].getClass());
   System.out.println(values[i]);
  }
 }
 TermsQueryBuilder(String name, String... values) {
  System.out.println("_____________________________________");
  System.out.println("String objects");
  for (int i = 0 ; i < values.length; i++) {
   System.out.println(values[i].getClass());
   System.out.println(values[i]);
  }
 }
}
Axel Richter
  • 56,077
  • 6
  • 60
  • 87
2

Simply rename one or both of your methods and the error will go away.

You cannot overload this method with the signatures your desire, because your call can be matched by both method definitions, and the types int and Object are not in a superclass-subclass relationship, so neither is more specific than the other.

Consider

integerTermsQuery

and

objectTermsQuery

EDIT

As you point out in your comments, the version with the String... parameter does not conflict with Object... and arrays are covariant with String being a subclass of Object.

Ray Toal
  • 86,166
  • 18
  • 182
  • 232
  • there are more methods like: public static TermsQueryBuilder termsQuery(String name, String... values) { return new TermsQueryBuilder(name, values); } when I called termsQuery("operationType", "1"); it is not ambiguous. these methods are from elasticsearch Java package. – Vic Aug 06 '17 at 04:51
  • Well that's correct because `String` is a subclass of `Object` and so the method with `String...` is more specific so it can be called without ambiguity. The problem here is with `int`. `int` is not a subclass of `Object`, but `Integer` is, even though `int` autoboxes to `Integer`. This is pretty tricky. Have you tried arrays? – Ray Toal Aug 06 '17 at 05:08
  • I tried termsQuery("operationType",Arrays.asList(searchParam.getOperatorType()) , not ambiguous. Thank u for your answer! – Vic Aug 06 '17 at 05:15
  • Hey, that's a nice approach. – Ray Toal Aug 06 '17 at 05:20
2

It's ambiguous because 1 can be automatically converted to Integer, which is accepted by the Object signature. It can also be directly accepted by the int signature.

You should make these two methods unambiguous, by either renaming the methods, or not having such a generic argument list (Object...)

Oleksi
  • 12,947
  • 4
  • 56
  • 80
  • 1
    Careful. The fact that 1 is both an int and an Object is not the whole story here. Note how the OP stated in the question that passing `"1"`, even though it is both a string and an object is **NOT** ambiguous. The problem being experienced by the OP is due to `int...` and `Object...` not being in a relationship that allows Java to choose the most specific method, based on the language definition. – Ray Toal Aug 06 '17 at 05:16