-
Notifications
You must be signed in to change notification settings - Fork 859
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
importClass usage that worked in 1.7.12 now fails in 1.7.14 #1463
Comments
Based on the lack of answers, it seems to me no one has an idea why this happens 🙄 You wouldn't have happened to make progress yourself figuring this out? My only suggestion at this point would to look at whether this behavior change happened in 1.7.13 or 1.7.14 and then to try to figure out which commit/merge caused the behaviour change... |
See #826 |
@tonygermano have you definitively determined that #826 indeed is the cause of the breakage? @Easy65 Any change to provide at least a testcase that reproduces the issue? |
@p-bakker: Sorry, I cannot provide a test case. This is a regression in a rather huge project were I am not familiar with the details. The people who implemented the functionality and the tests are no longer here. What I could do is running the tests with a patched version to check that it works again. Or to run the test case with an instrumented version of rhino that does some useful println to get an understanding of the situation. |
It is hard to definitively determine if that's the cause without a test case, but that seems like the likely culprit, as it is what introduced the changes to how the imports work between versions 1.7.13 and 1.7.14. |
I would be interested in seeing a test case that causes the rhino/rhino/src/main/java/org/mozilla/javascript/ImporterTopLevel.java Lines 211 to 220 in 7feaad0
The somewhat strange thing about how this method currently works is that if the same NativeJavaClass is found to have been already imported, we still do the put and "import" it over itself. I do a decent amount of Java interop, and I never use // I find this
const JSLongTest = Packages.path.to.JSLongTest
// preferable to
importClass(Packages.path.to.JSLongTest) You can even use destructuring to import and alias multiple classes from the same package at once const {Integer, String:JString} = java.lang
var s1 = String('this is a javascript string)
var s2 = new JString('this is a java.lang.String')
var i = Integer.valueOf(2) |
You are right!
this code cannot run, with error "Integer and JString are undefined" The bug has been verified, the "const" has too much bugs in many cases!
All right |
@p-bakker Sorry, I missed the mention. Can take a look next week |
As far as I found out, the following script fails importClass(java.util.Date)
importClass(java.util.Date) ... but this fails also on 1.7.12. (It would be really good, if we'll get more input here) |
Edit: sorry it is clear, that |
Hi, I finally had the time to create a test that is similar to the code that fails in our tests. |
I was able to identify the change in #826 as the cause of this issue. (You can find the tescase here: I'm happy to revise the change I made, but I think we need to first clarify what the correct or desired behavior is. Both @Eaysy65 and I want to use a SharedScope. While I do the following in #826 sharedScope = new ImporterTopLevel(tmpCtx, true); // define ImporterTopLevel as shared scope
sharedScope.sealObject();
scope1 = new NativeObject(); // use simple objects as context-scope
scope1.setPrototype(sharedScope); // and set the shared scope as prototype
script.exec(cx, scope1); is the initialization in the sample that @Easy65 provided as following sharedScope = cx.initStandardObjects(); // this is a NativeObject
Scriptable scope1 = new ImporterTopLevel(cx); // this would redefine standardObjects again
scope1.setParentScope(sharedScope);
script.exec(cx, scope1); As you see, this is the other way round and we have multiple TopLevelScopes, where the object is also the parentScope, which was not intended by me in #826. (One TopLevel scope and many small objects, that have the toplevel as prototype) I could of course say that Easy65's version is wrong, but I would like to hear a second opinion here. (I would also like to take a look at https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino/Scopes_and_Contexts#Sharing_Scopes, but the doc is gone and web.archive.org is currently offline) @Easy65 can you try to change your code as following: ScriptableObject init_scope = new ImporterTopLevel(js_ctx); // was: = js_ctx.initStandardObjects();
init_scope.sealObject(); // it is also a good idea to seal this
Scriptable scope = new NativeObject; // was: = new ImporterTopLevel(js_ctx);
scope.setPrototype(init_scope); // was: scope.setParentScope(init_scope); |
I changed this in the test class, but it fails if I add the sealObject() call, because of this line: Even if I changed this to: org.mozilla.javascript.EvaluatorException: Cannot modify a property of a sealed object: j_init_env. I try to change it also in our real code, but this is rather complex and I got it not working yet. |
@rPraml we host the docs ourselves: https://rhino.github.io/docs/scopes_and_contexts/#sharing-scopes |
I finally got it running in the real code, but also only without the After thinking a while about it, the correct way seems to seal the object after the variables are set. Would it be a problem to not seal the init_scope and allow to have multiple calls of I am not sure why a separate scope is used for every exec call. Is this to re-run with no variable values left from the previous run? And the question is still if our original code with setParentScope is really wrong or only an "unusual" way to use this. Regards, |
It seems that you (or the original author) wanted to use a shared scope as described here: https://rhino.github.io/docs/scopes_and_contexts/#sharing-scopes The idea of a shared scope is, that you init certain objects only once and reuse them in every exec call (initStandardObjects defines the standard javascript objects like
No. if the scope is not sealed, it may allow the current script to change things in the scope. You might pay attention, if the sealed scope is used in several threads (probably not in your use case).
Probably you could try to set Variable.INIT_ENV to your map in that scope. But I think it is required to have some basic understanding, what the intention of the original code was.
The implementation in your test case looks like an (incorrectly) implementation of the shared scope concept. (for example, it initalizes the standard objects on the init_scope and again on every call, which looks definitvely wrong or "unusual" in my eyes) But I do not know, what the original intention was. When we merge #1676, I think, your problem will disappear, but the code may be inperformant, as class caching will no longer work. (The reflection class cache resides in the ImporterTopLevel, which is not the toplevel in your case)
But I would still be happy if someone else could say something about the topic, because I'm not 100% sure about a few points either. Roland |
I guess the original author of this did not know much about the internals in Rhino, maybe he inherited the code from a former author and tried to get it working with these scopes/contexts. |
Hi,
we recently upgraded from version 1.7.12 to 1.7.14 and now one of our test fails.
The test uses importClass with a class in our JUnit tests and run the same script multiple times. We get this exception in 1.7.14:
org.mozilla.javascript.EvaluatorException: Cannot import "JSLongTest" since a property by that name is already defined. (TestJSScriptCode2#2)
at org.mozilla.javascript.DefaultErrorReporter.runtimeError(DefaultErrorReporter.java:79)
at org.mozilla.javascript.Context.reportRuntimeError(Context.java:907)
at org.mozilla.javascript.Context.reportRuntimeError(Context.java:963)
at org.mozilla.javascript.Context.reportRuntimeErrorById(Context.java:914)
at org.mozilla.javascript.ImporterTopLevel.importClass(ImporterTopLevel.java:216)
at org.mozilla.javascript.ImporterTopLevel.js_importClass(ImporterTopLevel.java:176)
at org.mozilla.javascript.ImporterTopLevel.execIdCall(ImporterTopLevel.java:257)
at org.mozilla.javascript.IdFunctionObject.call(IdFunctionObject.java:100)
at org.mozilla.javascript.optimizer.OptRuntime.callName(OptRuntime.java:59)
at org.mozilla.javascript.gen.TestJSScriptCode2_1._c_script_0(TestJSScriptCode2:2)
at org.mozilla.javascript.gen.TestJSScriptCode2_1.call(TestJSScriptCode2)
at org.mozilla.javascript.ContextFactory.doTopCall(ContextFactory.java:380)
at org.mozilla.javascript.ScriptRuntime.doTopCall(ScriptRuntime.java:3868)
at org.mozilla.javascript.gen.TestJSScriptCode2_1.call(TestJSScriptCode2)
at org.mozilla.javascript.gen.TestJSScriptCode2_1.exec(TestJSScriptCode2)
I tried to debug org.mozilla.javascript.ImporterTopLevel.importClass and compared the sources. There is now a scope object that is used instead of this, and there are 2 differences that I see:
In 1.7.12, the NativeJavaClass cl is always the same Java object. And we always have a new ImporterTopLevel object in each run, so cl is not found:
In 1.7.14, the NativeJavaClass cl is a different Java object (but equal) in each run. And the ImporterTopLevel object is the same on the second run, so the object is found, but not the same object, so the error occurs:
The code would probably work as expected, if the cl object would be the same Java object as it is in 1.7.12.
Any idea why this happens in 1.7.14?
Regards,
Andreas Mueller
The text was updated successfully, but these errors were encountered: