Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Multiple applicable overloads found" when it's not the case #286

Closed
shavitush opened this issue May 14, 2020 · 9 comments
Closed

"Multiple applicable overloads found" when it's not the case #286

shavitush opened this issue May 14, 2020 · 9 comments
Assignees
Labels
interop Polyglot Language Interoperability

Comments

@shavitush
Copy link

shavitush commented May 14, 2020

Caused by: org.graalvm.polyglot.PolyglotException: TypeError: invokeMember (print) on JavaObject[test.PrintTest@6de57597 (test.PrintTest)] failed due to: Multiple applicable overloads found for method name print (candidates: [Method[public void User.print(int,java.lang.String)], Method[public void User.print(int,int)]], arguments: [100000000 (Integer), 0 (Integer)])

This exception seems very wrong to me. I use ScriptEngine for the project with Nashorn compatibility mode. The exception message even says that I provided 2 integers and that one of the candidates accepts that for the arguments.

JS code:

function start(user)
{
    user.print(1, 3);
}

Java:

class User
{
    public void Print(int n1, int n2) { System.out.println(String.format("%d %d", n1, n2)); }
    public void Print(int n1, String n2) { System.out.println(String.format("%d %s", n1, n2)); }
}

((Invocable) scriptEngine).invokeFunction("start", new User());

I run OpenJDK 14 with graal.js from Maven.

With my testing, this code works fine with version 19.0.0 of org.graalvm.js.js and org.graalvm.js.js-scriptengine, but not on 19.3.2 or 20.0.0

@wirthi
Copy link
Member

wirthi commented May 14, 2020

Hi @shavitush

thanks for your report.

I have tried to reproduce your failure, but have not managed to. For me it works in all setups I have tried. I know that we had similar issues before, and cannot rule out that we still have them. Can you share "full" working example of your code, because the details seem to matter here.

BTW, in your example you have a deviation between upper and lower case print, but I assume that is a problem when copying the code here to GitHub, otherwise that would have caused a different error. And your User class needs to be public.

My working example is as follows:

test.js:

function start(user) {
  user.Print(1,3);
  user.Print(1,"test");
}

Main.java:

ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine engine = scriptEngineManager.getEngineByName("javascript");
Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
bindings.put("polyglot.js.allowIO", true);
bindings.put("polyglot.js.allowHostAccess", true);
bindings.put("polyglot.js.allowHostClassLookup", (Predicate<String>) s -> true);
engine.eval("load('test.js');");
((Invocable) engine).invokeFunction("start", new User());

User.java:

public class User {
    public void Print(int n1, int n2) { System.out.println(String.format("%d %d", n1, n2)); }
    public void Print(int n1, String n2) { System.out.println(String.format("%d %s", n1, n2)); }
}

@wirthi wirthi self-assigned this May 14, 2020
@wirthi wirthi added the interop Polyglot Language Interoperability label May 14, 2020
@iamstolis
Copy link
Member

@wirthi You are missing Nashorn compatibility mode. The described problem seems to be related to the Object to String conversion that is part of NASHORN_HOST_ACCESS. So, you should also remove bindings.put("polyglot.js.allowHostAccess", true); from your code to see the problem (as this line replaces NASHORN_HOST_ACCESS otherwise).

Unfortunately, I have no idea how to solve this issue. The mentioned target mapping (from Object to String) is needed in other situations (when the conversion is needed).

@wirthi
Copy link
Member

wirthi commented May 14, 2020

Thanks @iamstolis I missed that line in the text.

So, @shavitush , have you tried running outside Nashorn-compatibility mode? What usecase do you have that requires to set the Nashorn compatibility - it might be easier to solve or work around that problem.

Best,
Christian

@iamstolis
Copy link
Member

iamstolis commented May 14, 2020

@shavitush, does the workaround found by @wirthi accidentally work in your case, i.e., does the rest of your application works when you invoke

Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
bindings.put("polyglot.js.allowHostAccess", true);

during the initialization of ScriptEngine (before you use it for the first time)?

@Lzw2016
Copy link

Lzw2016 commented Aug 2, 2020

I encountered the same mistake Multiple applicable overloads found

TypeError: invokeMember 
Multiple applicable overloads found for method name info (candidates: [

Method[public void org.clever.hinny.api.internal.Logger.info(java.lang.String,java.lang.Object)], 
Method[public void org.clever.hinny.api.internal.Logger.info(java.lang.String,java.lang.Throwable)], 
Method[public void org.clever.hinny.api.internal.Logger.info(java.lang.String,java.lang.Object[])]


],
 arguments: [order_id -> {} (String), DynamicObject<undefined>@561953e3 (DynamicObjectBasic)])

Java Code

public void info(String msg) {
    Object[] args = new Object[]{};
    info(msg, args);
}

public void info(String format, Object arg) {
    Object[] args = new Object[]{arg};
    info(format, args);
}

public void info(String format, Object arg1, Object arg2) {
    Object[] args = new Object[]{arg1, arg2};
    info(format, args);
}

public void info(String msg, Throwable t) {
    Object[] args = new Object[]{t};
    info(msg, args);
}

/**
 * info打印输出
 *
 * @param args 输出数据
 */
public void info(String format, Object... args) {
    if (logger.isInfoEnabled()) {
        TupleTow<String, Throwable> tupleTow = logString(format, args);
        if (tupleTow.getValue2() == null) {
            logger.info(tupleTow.getValue1());
        } else {
            logger.info(tupleTow.getValue1(), tupleTow.getValue2());
        }
    }
}

JavaScript Code

log.info("order_id -> {}", undefined);

Lzw2016 added a commit to Lzw2016/clever-hinny that referenced this issue Aug 2, 2020
@Lzw2016
Copy link

Lzw2016 commented Aug 3, 2020

因为 JavaScript undefined 传到Java中是 null, 所以才会报错 "Multiple applicable overloads found"

最上面的例子:

JavaScript

function start(user)
{
    user.print(1, 3);          // 这样没有问题
    user.print(1, undefined);  // 这里有问题! fixme,  undefined -> null
}

Java

class User
{
    public void Print(int n1, Integer n2) { System.out.println(String.format("%d %d", n1, n2)); }
    public void Print(int n1, String n2) { System.out.println(String.format("%d %s", n1, n2)); }
}

@pavel-borik
Copy link

Hello, as a part of the migration process from Nashorn, I am trying to solve the problem with the automatic type conversions that Nashorn provided. We have quite extensive amount of methods available through bindings, and the conversion rules defined in the HostAccess builder looked promising. I intended to use it for the Boolean <-> String <-> Number conversions.

However, there is the "Multiple applicable overloads" problem for every sourceType and targetType pair, when there is an overloaded method accepting both of these - for example Integer Java class constructor accepting String and int:

    @Test
    public void testTargetTypeMapping() {
        Context context = Context.newBuilder()
                .allowHostAccess(HostAccess.newBuilder(HostAccess.ALL)
                        //.targetTypeMapping(Object.class, String.class, Objects::nonNull, String::valueOf)
                        .targetTypeMapping(String.class, Integer.class, (v) -> parseIntOrNull(v) != null, GraalTest::parseIntOrNull)
                        .targetTypeMapping(List.class, Object.class, v -> {
                            final Value it = Value.asValue(v);
                            return it.hasMembers() && it.hasArrayElements();
                        }, v -> v)
                        .build())
                .allowHostClassLookup(s -> true)
                .allowIO(true)
                .allowCreateThread(true)
                .allowCreateProcess(true)
                .allowExperimentalOptions(true)
                .option("js.nashorn-compat", "true")
                .option("js.ecmascript-version", "2020")
                .build();


        String script = "var Integer = Java.type(\"java.lang.Integer\");\n" +
                "var myInt = new Integer(\"50\");\n" +
                "var myInt2 = new Integer(50);";
        context.eval("js", script);
    }

    private static Integer parseIntOrNull(String s) {
        try {
            return Integer.parseInt(s);
        } catch (NumberFormatException ex) {
            return null;
        }
    }

When run like this, line 3 of the script fails. When I uncomment the Object -> String targetTypeMapping, line 2 of the script fails (both with the Multiple applicable overloads found for method name java.lang.Integer).

What is the recommended procedure of handling the Nashorn - Graal migration regarding this issue? The only option I could think of is replacing the parameter types of all the Bindings' methods to Value and parse it myself. Is there a plan to fix this issue in the future?

@iamstolis
Copy link
Member

iamstolis commented Oct 27, 2020

The latest development builds (and the soon to be released GraalVM 20.3) allow you to specify the priority/precedence of the target type mappings. So, your test-case works there if you lower the precedence of some of your mappings. For example, you can use

.targetTypeMapping(Object.class, String.class, Objects::nonNull, String::valueOf, HostAccess.TargetMappingPrecedence.LOWEST)
.targetTypeMapping(String.class, Integer.class, (v) -> parseIntOrNull(v) != null, DeleteMe::parseIntOrNull, HostAccess.TargetMappingPrecedence.LOW)

@wirthi
Copy link
Member

wirthi commented Nov 20, 2020

GraalVM 20.3 has been released. As @iamstolis described in the previous message, you can now specify the precedence of targetTypeMappings.

I am closing this ticket. If you still cannot make your code work based on GraalVM 20.3 and precedences set properly, please open a new ticket with a short reproducer so we can investigate, thanks.

@wirthi wirthi closed this as completed Nov 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
interop Polyglot Language Interoperability
Projects
None yet
Development

No branches or pull requests

6 participants