JDK-8171849 : Can't unambiguously select between fixed arity signatures [(java.util.Collection), (java.util.Map)]
  • Type: Bug
  • Component: core-libs
  • Sub-Component: jdk.nashorn
  • Affected Version: 8u60,9
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2016-12-20
  • Updated: 2017-11-29
  • Resolved: 2016-12-22
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u152Fixed 9 b151Fixed
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.8.0_111"
Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Darwin acbc32c7fb93.ant.amazon.com 15.6.0 Darwin Kernel Version 15.6.0: Thu Sep  1 15:01:16 PDT 2016; root:xnu-3248.60.11~2/RELEASE_X86_64 x86_64

A DESCRIPTION OF THE PROBLEM :
Given a class like this:

public class MapAndList {
	public void test(Map<String, Object> map) {
	}

	public void test(List<Object> collection) {
	}
}

Nashorn fails to call the function "test" with an array:
e.g. instance.test([1,2,3]) will result in java.lang.NoSuchMethodException: Can't unambiguously select between fixed arity signatures [(java.util.Collection), (java.util.Map)] ...


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the following code:

public class MapAndList {
	public void test(Map<String, Object> map) {
	}

	public void test(List<Object> collection) {
	}
}

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.put("mapcoll", new MapAndCollection());
engine.eval("mapcoll.test([1,2,3]);");


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The call succeeds.
ACTUAL -
java.lang.RuntimeException: java.lang.NoSuchMethodException: Can't unambiguously select between fixed arity signatures [(java.util.Collection), (java.util.Map)] of the method NashornCollectionArityBugTest.MapAndCollection.test for argument types [jdk.nashorn.internal.objects.NativeArray]

ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.lang.RuntimeException: java.lang.NoSuchMethodException: Can't unambiguously select between fixed arity signatures [(java.util.Collection), (java.util.Map)] of the method NashornCollectionArityBugTest.MapAndCollection.test for argument types [jdk.nashorn.internal.objects.NativeArray]
	at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:397)
	at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:446)
	at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:403)
	at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:399)
	at jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:155)
	at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)
	at NashornCollectionArityBugTest.mapVsCollectionArityBug(NashornCollectionArityBugTest.java:54)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: java.lang.NoSuchMethodException: Can't unambiguously select between fixed arity signatures [(java.util.Collection), (java.util.Map)] of the method NashornCollectionArityBugTest.MapAndCollection.test for argument types [jdk.nashorn.internal.objects.NativeArray]
	at jdk.internal.dynalink.beans.OverloadedMethod.throwAmbiguousMethod(OverloadedMethod.java:225)
	at jdk.nashorn.internal.scripts.Script$1$\^eval\_.:program(<eval>:1)
	at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:637)
	at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:494)
	at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:393)
	... 29 more



REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.util.Collection;
import java.util.List;
import java.util.Map;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import org.junit.Test;

public class NashornCollectionArityBugTest {
	ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");

	@SuppressWarnings("unused")
	public class MapAndList {
		public void test(Map<String, Object> map) {
		}

		public void test(List<Object> collection) {
		}
	}

	@SuppressWarnings("unused")
	public class MapAndCollection {
		public void test(Map<String, Object> map) {
		}

		public void test(Collection<Object> collection) {
		}
	}

	@Test
	public void mapVsListArity() throws ScriptException {
		// Given I have a method that can take either a Map or a List
		engine.put("maplist", new MapAndList());

		// When I call the method with an NativeArray parameter
		engine.eval("maplist.test([1,2,3]);");

		// Then call should succeed
	}

	// As of Java(TM) SE build 1.8.0_111-b14 this will fail with:
	// java.lang.NoSuchMethodException: Can't unambiguously select between fixed arity signatures [(java.util.Collection), (java.util.Map)] of the method NashornCollectionArityBugTest.MapAndCollection.test for argument types [jdk.nashorn.internal.objects.NativeArray]

	@Test
	public void mapVsCollectionArityBug() throws ScriptException {
		// Given I have a method that can take either a Map or a Collection
		engine.put("mapcoll", new MapAndCollection());

		// When I call the method with an NativeArray parameter
		engine.eval("mapcoll.test([1,2,3]);");

		// Then call should succeed
	}

}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Can be worked around if can change the signature from Collection to a more restrictive List


Comments
It seems like when I implemented JDK-8081015 (which introduced conversion of Arrays to Collection and Queue in addition to List and Deque), I haven't updated NashornLinker.isList() that's used by NashornLinker.compareConversion to prioritize the conversions of Arrays. That's why it prioritizies List over Map as conversion target, but doesn't prioritize Collection over anything. I suggest isList() should be renamed to isArrayPreferredTargetType() or something and its body changed to: return clazz == List.class || clazz == Collection.class || clazz == Queue.class || clazz == Deque.class NB: there's no preference for one over the other of these, so people can still create ambiguity by declaring one method that takes a List and another that takes a Queue or Deque, as Queue and Deque extend Collection, but don't extend List.
22-12-2016

Checked the issue against 8,8u40,8u51,8u52ea,8u60,8u112,8u122ea,9ea on Windows 7 and could reproduce the issue on 8u60 and onwards. Steps to reproduce(javac): ************************** - Run the attached file(NashornCollectionArityBugTest.java) with JDK. Result: ********* OS : Microsoft Windows 7 Professional 64 bit [Version 6.1.7601], JDK: ++++ 8 b132 : Pass 8u40 b26: Pass 8u51 b16 : Pass 8u52 b07 : Pass >>8u60 b27 : Fail <====== Introduced in Version 8u112 b15 : Fail 8u122ea b04 : Fail 9ea+148 : Fail ================================================================
21-12-2016