Subject:
JavaAdapter return type conversion
Date:
Wed, 19 Apr 2000 12:12:47 +0100
From:
Matthias Radestock <rade@logee.com>
Organization:
Logee
To:
norris@netscape.com
CC:
mccabe@netscape.com, beard@netscape.com, rogerl@netscape.com
Dear Rhino team,
When returning an array from a scripted Java object (i.e. a JS object
that implements a Java interface), no type conversion is performed, ie.
a NativeArray is returned instead of a Java array. Example:
Java:
interface Foo {
public String[] boo();
}
JS:
FooI = {
boo: function() { return ["Boo"];}
}
myFoo = new Packages.Foo(FooI);
myFoo.boo(); //==> breaks with a ClassCastException
Looking at the JavaAdapter code, there is no code for array conversion.
This is particularly bad because precisely such a conversion *does*
happen when calling a Java method from JS. So we end up with a
discrepancy.
See attachment for a patch to fix this and little test program. The
patch works by calling the coerceType function on NativeJavaObject,
which is the function responsible for doing the conversion when calling
from JS to Java. I've simplified the code so that this function gets
called for all non-primitive return type, not just arrays. There are
probably more efficient solutions but I'm not a Java bytecode hacker.
Matthias
PS: I didn't open a bug for this because I wasn't sure whether you guys
would agree that this is indeed a problem ;)
public interface JSReturnTest {
public boolean returnBoolean();
public char returnChar();
public int returnInt();
public String returnString();
public org.mozilla.javascript.Scriptable returnScriptable();
public Object returnObject();
public boolean[] returnBooleanA();
public char[] returnCharA();
public int[] returnIntA();
public String[] returnStringA();
public org.mozilla.javascript.Scriptable[] returnScriptableA();
public Object[] returnObjectA();
public Object[][] returnObjectAA();
}
Index: JavaAdapter.java
===================================================================
RCS file: /cvsroot/mozilla/js/rhino/org/mozilla/javascript/JavaAdapter.java,v
retrieving revision 1.21
diff -r1.21 JavaAdapter.java
54c54,59
<
---
>
> public static Object convertResult(Object result, String classname)
> throws ClassNotFoundException {
> return NativeJavaObject.coerceType(Class.forName(classname),
> result);
> }
467,474c472,474
< } else if (retType.equals(String.class)) {
< cfw.add(ByteCode.INVOKESTATIC,
< "org/mozilla/javascript/Context",
< "toString", "(Ljava/lang/Object;)",
< "Ljava/lang/String;");
< cfw.add(ByteCode.ARETURN);
< } else if (retType.equals(Scriptable.class)) {
< cfw.add(ByteCode.ALOAD_0); // load 'this' to find scope from
---
> } else {
> String retTypeStr = retType.getName();
> cfw.addLoadConstant(retTypeStr);
476,477c476,477
< "org/mozilla/javascript/Context",
< "toObject",
---
> "org/mozilla/javascript/JavaAdapter",
> "convertResult",
479,500c479,480
< "Lorg/mozilla/javascript/Scriptable;)",
< "Lorg/mozilla/javascript/Scriptable;");
< cfw.add(ByteCode.ARETURN);
< } else {
< // If it is a wrapped type, cast to Wrapper and call unwrap()
< cfw.add(ByteCode.DUP);
< cfw.add(ByteCode.INSTANCEOF, "org/mozilla/javascript/Wrapper");
< // skip 3 for IFEQ, 3 for CHECKCAST, and 5 for INVOKEINTERFACE
< cfw.add(ByteCode.IFEQ, 11);
< cfw.add(ByteCode.CHECKCAST, "org/mozilla/javascript/Wrapper");
< cfw.add(ByteCode.INVOKEINTERFACE,
< "org/mozilla/javascript/Wrapper",
< "unwrap", "()", "Ljava/lang/Object;");
<
< // If Undefined, return null
< cfw.add(ByteCode.DUP);
< cfw.add(ByteCode.INSTANCEOF, "org/mozilla/javascript/Undefined");
< // skip 3 for IFEQ, 1 for ACONST_NULL, 1 for ARETURN
< cfw.add(ByteCode.IFEQ, 5);
< cfw.add(ByteCode.ACONST_NULL);
< cfw.add(ByteCode.ARETURN);
<
---
> "Ljava/lang/String;)",
> "Ljava/lang/Object;");
502,503c482
< String retTypeStr = retType.getName().replace('.', '/');
< cfw.add(ByteCode.CHECKCAST, retTypeStr);
---
> cfw.add(ByteCode.CHECKCAST, retTypeStr.replace('.', '/'));
testpatch.js
Name:
testpatch.js
Type:
JavaScript Program (application/x-javascript)
Encoding:
7bit
contextClassloader problem in ScriptRuntime.java
Date:
Tue, 11 Apr 2000 09:45:36 -0400
From:
"Howard Lin" <howard@softcom.com>
To:
"Norris Boyd" <norris@netscape.com>
CC:
"Andrew Wason" <aw@softcom.com>
Hi, Norris, we are trying to create a Java class in JavaScript. When security manager is on, everything works fine. But when security
manager is off, we got an error saying the "... is not defined". The problem is that in ScriptRuntime.java, when security is on,
getContextClassLoader is null due to SecurityException and Class.forName is used to find the class, which works fine. When security
is off, ContextClassLoaderMethod is invoked to find the class. Since we use a separate thread to load third party jar files,
ContextClassLoaderMethod will throw a ClassNotFound exception.
To illustrate this problem, I wrote a simple applet, evaluating a simple js file in its paint method, which is running on a separate thread.
When security is off, I got the following:
ReferenceError: "Global" is not defined.
at org.mozilla.javascript.NativeGlobal.constructError(NativeGlobal.java:
494)
at org.mozilla.javascript.ScriptRuntime.name(ScriptRuntime.java, Compile
d Code)
at org.mozilla.javascript.Interpreter.interpret(Interpreter.java, Compil
ed Code)
at org.mozilla.javascript.InterpretedScript.call(InterpretedScript.java:
67)
at org.mozilla.javascript.InterpretedScript.exec(InterpretedScript.java:
54)
at org.mozilla.javascript.Context.evaluateReader(Context.java:739)
at test.evaluate(test.java:26)
at test.paint(test.java:16)
at sun.awt.windows.WComponentPeer.handleEvent(WComponentPeer.java:117)
at java.awt.Component.dispatchEventImpl(Component.java:2447)
at java.awt.Container.dispatchEventImpl(Container.java:1035)
at java.awt.Component.dispatchEvent(Component.java:2307)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:287)
at java.awt.EventDispatchThread.pumpOneEvent(EventDispatchThread.java:10
1)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:92)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:83)
When security is on, it runs fine. Or if the code moved to init method, it works fine regardless of security. We are using JDK 1.2.2.
Howard
step += (InLeapYear(t) ? 29 : 28);
with the form
if (InLeapYear(t))
step += 29;
else
step += 28;
to work around an apparent JRE bug in which the code always returns 28.
2. Change from using Class.getDeclaredMethods to Class.getMethods since the former may cause
security problems. Implement a cache to ameleorate the possible performance degredation.
3. Add a new class to lazily load constructors to improve performance
This was caused by a previous bug fix in which I moved the try stack
decrement to the end of the catch clause because it was getting skipped
by the final statement in the try block (which is always a goto around the
catch block). Better is to make sure the endTry is the statment just before
that goto, and do the try stack decrement in the catch the way god intended.
Subject:
Rhino request URGENT
Date:
Thu, 02 Dec 1999 15:58:40 -0500
From:
slobo@espialgroup.com
To:
Norris Boyd <norris@netscape.com>
References:
1 , 2
Hello Norris
In Rhino, the following script gives the error : "function does not always return a value" during the parsing phase. The script
runs perfectly fine in Netscape 4.61. It is an urgent requirement. Many thanks in advance.
Steven
///////////////////////////////////////////////////////SCRIPT BEGIN ///////////////////////////////////////////////
function test (a) {
this.arg = a;
if (a>20)
return;
return this;
}
//print = alert;
function joe() {
a = new test (20);
print (a.arg);
a = new test (25);
print (a.arg);
}
joe();
///////////////////////////////////////////////////////SCRIPT END ///////////////////////////////////////////////