-
Notifications
You must be signed in to change notification settings - Fork 850
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
Non deterministic behaviour with vararg methods #1433
base: master
Are you sure you want to change the base?
Conversation
} | ||
|
||
@Test | ||
public void args2TestJs() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same test, but different order. If using HashMap instead of LinkedHashMap, I cannot provide stable failing tests
@@ -308,7 +309,8 @@ private Object getExplicitFunction( | |||
*/ | |||
private Method[] discoverAccessibleMethods( | |||
Class<?> clazz, boolean includeProtected, boolean includePrivate) { | |||
Map<MethodSignature, Method> map = new HashMap<>(); | |||
Map<MethodSignature, Method> map = | |||
new LinkedHashMap<>(); // use linked hash map for deterministic discovery |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To discuss: Should we make this change? It would help to add determinism (as long as the JVM's getDeclaredMethods returns them in the same order as in source code)
I think that this change makes sense and fixes a bug, and I'm fine with using LinkedHashMap here so that it's deterministic. However, I don't currently work on anything that uses all of the Java reflection stuff in Rhino, and I'd love an opinion by another regular user who works with Rhino this way to make sure that we're not missing anything. Thanks! |
@gbrail I've resolved merge commits here |
Never ran into this, but LGTM @andreabergia @tonygermano care to comment on this one as well, given that both of you seem to use Java Interop in your Rhino integrations |
Looks good to me! |
I haven't reviewed the code, but the stated fix of making the behavior match what java does seems correct to me. |
Here's some information about how java resolves overloads. https://stackoverflow.com/a/27880923 |
Looking at the java spec, I think it should be the very first check in the This does 2 things,
Edit: I think the current algorithm could even end up preferring the vararg method over the other, depending on the types, which would be also be wrong. In section 15.12.2, the note following phase 2 states,
|
Can you take a look at the comments by @tonygermano and let us know what you think? Thanks! |
@tonygermano thanks for feedback
I'm unsure. If I do the check at top of the method, I will always prefer Thanks for the link to java spec. I've extended the test cases, but I think there is still one failing case. when an array is passed |
Converted to draft, as it currently doesn't pass the CI build |
Summary
If there are two methods, one with varargs and an other without, for example
String args(String arg1, String... args)
String args(String arg1)
rhino considers these two methods as
PREFERENCE_EQUAL
when it is invoked withargs('foo')
from javascript. This may result in a non deterministic behaviour as one of the two was taken.Details
In the case described above, all methods are compared and it is tried to find the best matchin one. So after
preferSignature
we will run into this code part inNativeJavaMethod
In our application, where the bug occured, we run in the
Ignoring same signature member
code path and one (not really deterministic - because of HashMap) method was taken. So the code sometimes works and sometimes not.It was also not easy to provide a deterministic failing test, that's why (and maybe to add more determinism) I've changed the map in
discoverAccessibleMethods
to a LinkedHashMap (and yet the test depends heavily on the order of the JVM'sgetDeclaredMethods
implementation)Fix
When there are two candidates, the no-vararg method is taken. This is the same behaviour, as it is in Java.