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

importClass usage that worked in 1.7.12 now fails in 1.7.14 #1463

Open
Easy65 opened this issue Apr 5, 2024 · 9 comments
Open

importClass usage that worked in 1.7.12 now fails in 1.7.14 #1463

Easy65 opened this issue Apr 5, 2024 · 9 comments
Labels
bug Issues considered a bug Regression

Comments

@Easy65
Copy link

Easy65 commented Apr 5, 2024

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:

private void importClass(NativeJavaClass cl)
{
    String s = cl.getClassObject().getName();
    String n = s.substring(s.lastIndexOf('.')+1);
    Object val = get(n, this);
    if (**val != NOT_FOUND** && val != cl) {
        throw Context.reportRuntimeError1("msg.prop.defined", n);
    }
    //defineProperty(n, cl, DONTENUM);
    put(n, this, cl);
}

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:

private static void importClass(Scriptable scope, NativeJavaClass cl) {
    String s = cl.getClassObject().getName();
    String n = s.substring(s.lastIndexOf('.') + 1);
    Object val = scope.get(n, scope);
    if (val != NOT_FOUND && **val != cl**) {
        **throw Context.reportRuntimeErrorById("msg.prop.defined", n);**
    }
    // defineProperty(n, cl, DONTENUM);
    scope.put(n, scope, cl);
}

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

@p-bakker
Copy link
Collaborator

p-bakker commented Jun 22, 2024

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...

@p-bakker p-bakker added Regression bug Issues considered a bug labels Jun 22, 2024
@tonygermano
Copy link
Contributor

See #826

@p-bakker
Copy link
Collaborator

@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?

@Easy65
Copy link
Author

Easy65 commented Jul 19, 2024

@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.

@tonygermano
Copy link
Contributor

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.

@p-bakker
Copy link
Collaborator

@rPraml does this ring any bells for you, given that you authored the #826 PR?

@tonygermano
Copy link
Contributor

I would be interested in seeing a test case that causes the NativeJavaClass in the second parameter to be the same object in 1.7.12, but different (but equal) objects in 1.7.14. If that is what is happening, would the fix be as simple as changing line 215 to if (val != NOT_FOUND && !cl.equals(val)) {?

private static void importClass(Scriptable scope, NativeJavaClass cl) {
String s = cl.getClassObject().getName();
String n = s.substring(s.lastIndexOf('.') + 1);
Object val = scope.get(n, scope);
if (val != NOT_FOUND && val != cl) {
throw Context.reportRuntimeErrorById("msg.prop.defined", n);
}
// defineProperty(n, cl, DONTENUM);
scope.put(n, scope, cl);
}

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 importClass.

// 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)

@anonyein
Copy link

anonyein commented Jul 20, 2024

I would be interested in seeing a test case that causes the NativeJavaClass in the second parameter to be the same object in 1.7.12, but different (but equal) objects in 1.7.14. If that is what is happening, would the fix be as simple as changing line 215 to if (val != NOT_FOUND && !cl.equals(val)) {?

private static void importClass(Scriptable scope, NativeJavaClass cl) {
String s = cl.getClassObject().getName();
String n = s.substring(s.lastIndexOf('.') + 1);
Object val = scope.get(n, scope);
if (val != NOT_FOUND && val != cl) {
throw Context.reportRuntimeErrorById("msg.prop.defined", n);
}
// defineProperty(n, cl, DONTENUM);
scope.put(n, scope, cl);
}

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 importClass.

// 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!

const {Integer, String:JString} = Packages.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)

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!

var {Integer, String:JString} = Packages.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)

All right

@p-bakker
Copy link
Collaborator

@rPraml any chance you could have a look to see if your #826 PR might be the culprit of this regression

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issues considered a bug Regression
Projects
None yet
Development

No branches or pull requests

4 participants