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

Backward compatibility java.util.{List,Map} interop #820

Closed
tuchida opened this issue Jan 5, 2021 · 12 comments · Fixed by #836
Closed

Backward compatibility java.util.{List,Map} interop #820

tuchida opened this issue Jan 5, 2021 · 12 comments · Fixed by #836
Labels
Java Interop Issues related to the interaction between Java and JavaScript

Comments

@tuchida
Copy link
Contributor

tuchida commented Jan 5, 2021

ref. #713

var h = new java.util.HashMap();
h.put('a', 123);
h.a;  // 123.0
h.put('put', 123);
h.put; // 123.0
h.put('put', 123);
// js: "<stdin>", line 7: uncaught JavaScript runtime exception: TypeError: Cannot call property put in object {a=123.0, put=123.0}. It is not a function, it is "object".
//	at <stdin>:7
  • Is it possible to have problems with code written in the past?
  • Is there a how to make sure to call java.util.HashMap#put?
@tuchida
Copy link
Contributor Author

tuchida commented Jan 5, 2021

Treating JS Object like HashMap has various problems (e.g. __proto__). I think you should consider compatibility between ES6 Map and java.util.Map.

@tuchida
Copy link
Contributor Author

tuchida commented Jan 5, 2021

Is there a how to make sure to call java.util.HashMap#put?

var h = new java.util.HashMap();
var put = h.put;
put.call(h, 'a', 123);
h; // {a=123.0}
put.call(h, 'put', 123);
put.call(h, 'put', 456);
h; // {a=123.0, put=456.0}

@tuchida
Copy link
Contributor Author

tuchida commented Jan 5, 2021

var a = new java.util.HashMap();
a.put('1', 123);
a['1']; // js: Java class "java.util.HashMap" has no public instance field or method named "1".

a['1']; calls public Object get(int index, Scriptable start).

public Object get(int index, Scriptable start) {
if (map.containsKey(Integer.valueOf(index))) {
Context cx = Context.getContext();
Object obj = map.get(Integer.valueOf(index));
return cx.getWrapFactory().wrap(cx, this, obj, obj.getClass());

@tuchida
Copy link
Contributor Author

tuchida commented Jan 7, 2021

@gbrail This issue can be critical. What do you think?

@gbrail
Copy link
Collaborator

gbrail commented Jan 8, 2021

This seemed like a nice convenience function, but you're right that it results in JavaScript objects that behave in strange ways, and it indeed means that things work a bit differently than they did before. Unfortunately we did a release since then, although I don't know how many people are using it. Perhaps we should add a feature flag on the Context object so that this functionality is not enabled by default.

I can see the attraction of making it possible for the JavaScript Map and Set to be made interoperable with existing Java Map and Set classes, but unfortunately the iteration semantics are very different and the result would be Map and Set objects that don't work like JavaScript Maps and Sets anyway.

@tuchida
Copy link
Contributor Author

tuchida commented Jan 8, 2021

Thank you for looking.
For example, browser's localStorage looks like this:

localStorage.setItem('a', 1);
localStorage.a; // 1
localStorage.setItem('setItem', 1);
localStorage.setItem; // function
localStorage.setItem('1', 1);
localStorage['1']; // 1
localStorage[1]; // 1

Perhaps emulating this would be a little better.

@syjer
Copy link
Contributor

syjer commented Jan 8, 2021

Hi, as a I proposed this PR, the goal was a better compatibility with nashorn, which allow this kind of java map <-> js object behaviour. My guess would be to check how they handled this cases.

@gbrail
Copy link
Collaborator

gbrail commented Jan 8, 2021 via email

@tuchida
Copy link
Contributor Author

tuchida commented Jan 9, 2021

Nashorn:

// $ jjs -v
// nashorn 1.8.0_275
var h = new java.util.HashMap();
h.put; // [jdk.internal.dynalink.beans.SimpleDynamicMethod Object java.util.HashMap.put(Object,Object)]
h.put('put', 1);
h.put('put', 2);   // OK
(h.put)('a', 2);  // OK
var put = h.put;
put('a', 2); // <shell>:1 TypeError: put is not a function
(0, h.put)('a', 2);  // <shell>:1 TypeError: 0 ,> h.put is not a function

Rhino:

(function() {
  eval("var x = 1;");
  (0, eval)("var x = 2;");
  print(x); // 1
}());
print(x); // 2

https://github.com/tc39/test262/blob/041da54c02ae7d17edb8c134ab7691c4f643bafe/test/language/eval-code/indirect/var-env-var-non-strict.js
Is it feasible with Icode_CALLSPECIAL?

@tuchida
Copy link
Contributor Author

tuchida commented Jan 16, 2021

var h = new java.util.HashMap();
h.put(new String('abc'), 1);
h.put(new String('abc'), 2);
JSON.stringify(Object.keys(h)); // ["abc","abc"]

@tuchida
Copy link
Contributor Author

tuchida commented Feb 14, 2021

ref. #839

@tuchida
Copy link
Contributor Author

tuchida commented Feb 20, 2021

ref. #836
It is now disabled.
Probably the problem occurs only with NativeJavaMap, and NativeJavaList is not a problem since it only accesses numbers.

@tuchida tuchida closed this as completed Feb 20, 2021
@p-bakker p-bakker added this to the Release 1.7.14 milestone Jan 20, 2022
@p-bakker p-bakker added the Java Interop Issues related to the interaction between Java and JavaScript label Jan 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Java Interop Issues related to the interaction between Java and JavaScript
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants