mozilla / rhino

Rhino is an open-source implementation of JavaScript written entirely in Java
https://rhino.github.io
Other
4.18k stars 851 forks source link

The choice of Java method java.lang.String.replace matching JavaScript argument types (function,string) is ambiguous #1633

Closed dhavkuma closed 1 month ago

dhavkuma commented 2 months ago

The code where this ambiguity occurs is resource.getPath().replace(/\W/g, '').replace(/+/g, '_')

The question still open is:

why replace(/\W/g, '') or replace(/+/g, '_') is matching to replace(function, string)

i.e. a regular expression matches with a function-type argument.

Earlier issue https://github.com/mozilla/rhino/issues/1632 answered the part about method overloading.

tonygermano commented 2 months ago

I'm not sure if I understand your question.

java Strings and Arrays are somewhat unique among Java objects because they are allowed to use String.prototype and Array.prototype methods as long as there is not a java method of the same name. String.replace is a commonly used method which has this conflict. So is String.split.

So, you really just need to choose which replace method you want to use, and then ensure you are working with the correct String type.

If you want to use javascript replace, ensure you are starting with a javascript string

String(resource.getPath()).replace(/\W/g, '').replace(/+/g, '_')

If you want to use java regex replace, you can't pass a javascript RegExp object as an argument. The java method String.replace is actually normal string replacement. The Java regex replace methods are replaceFirst and replaceAll and take the regex as a string (java does not have a literal regex notation.) In your case, you want to use replaceAll, because of the g flag. Since you are in a string now, don't forget to escape your escapes.

// if you aren't sure what your object is starting out as
var javaString = new java.lang.String(obj)
javaString.replaceAll('\\W', '').replaceAll('\\+', '_')

In the future, please open questions like this as a Discussion post. If it's determined that there really is an issue with Rhino, it can be converted to an Issue.

dhavkuma commented 2 months ago

With the code we were getting this

ERROR: The choice of Java method java.lang.String.replace matching JavaScript argument types (function,string) is ambiguous

The question here was why the first argument which is a regular expression converts to a function.

Stacktrace:

Caused by: org.mozilla.javascript.EvaluatorException: The choice of Java method java.lang.String.replace matching JavaScript argument types (function,string) is ambiguous; candidate methods are: _ class java.lang.String replace(java.lang.CharSequence,java.lang.CharSequence)_ class java.lang.String replace(char,char) (/libs/screens/core/components/content/video/video.js#169) at org.mozilla.javascript.DefaultErrorReporter.runtimeError(DefaultErrorReporter.java:77) at org.mozilla.javascript.Context.reportRuntimeError(Context.java:954) at org.mozilla.javascript.Context.reportRuntimeError(Context.java:1010) at org.mozilla.javascript.Context.reportRuntimeError4(Context.java:997) at org.mozilla.javascript.NativeJavaMethod.findFunction(NativeJavaMethod.java:468) at org.mozilla.javascript.NativeJavaMethod.findCachedFunction(NativeJavaMethod.java:262) at org.mozilla.javascript.NativeJavaMethod.call(NativeJavaMethod.java:139) at org.mozilla.javascript.optimizer.OptRuntime.call2(OptRuntime.java:42) [org.apache.servicemix.bundles.rhino:1.7.7.1_1] at org.mozilla.javascript.gen._libs_screens_core_components_content_video_video_js_20._c_anonymous_1(/libs/screens/core/components/content/video/video.js:169)

tonygermano commented 2 months ago

When I do it, it says object instead of function:

js> new java.lang.String().replace(/\W/g, '')
js: The choice of Java method java.lang.String.replace matching JavaScript argument types (object,string) is ambiguous; candidate methods are: 
    class java.lang.String replace(java.lang.CharSequence,java.lang.CharSequence)
    class java.lang.String replace(char,char)
        at (unknown):22

But that is not what is causing your problem. Your problem is that you are passing a javascript regexp to a java method that expects either a char or a CharSequence as the first argument, and it can't figure out what you were trying to do.

Use one of the two methods I already suggested:

  1. make it a javascript string if you want to call String.prototype.replace with a javascript regexp
  2. call replaceAll instead of replace on a java String and pass it a string instead of a js regexp as the first arg, as the method expects

This will prevent any errors about ambiguity.

dhavkuma commented 2 months ago

Thanks @tonygermano. We took your suggestion and refactored the code to java.lang.String(resource.getPath()).replaceAll('\\W', '_').replaceAll('_+', '_'); which would solve the ambiguity which occurred.

However, please note this error occurs intermittently on our runtime. Could you please suggest what might cause this inconsistent behaviour on rhino processing on the same piece of code?

tonygermano commented 2 months ago

You will never see that message unless you are calling an overloaded java method with values that make the runtime unsure which method you intended to call. Very rarely you need to explicitly choose which overloaded java method to call since you cannot cast values in javascript, but if you are not trying to call a java method in the first place, then you need to fix your code. In this case, it was expecting the first argument to be either a CharSequence or a char, and you were passing an object that was neither of those.

The error probably saved you in this case, because if the method was only expecting a CharSequence, it likely would have used the .toString value of your regex, which would definitely not have produced the results that you were looking for.

p-bakker commented 1 month ago

Closing this one, as there doesn't seem to be an issue here

Feel free to reopen if there's an actual issue, preferable with a reproducible example