diff --git a/js/src/liveconnect/README.html b/js/src/liveconnect/README.html
index ee1e9b51534..4bf28cb5bce 100644
--- a/js/src/liveconnect/README.html
+++ b/js/src/liveconnect/README.html
@@ -50,8 +50,7 @@ were integrated with Netscape Navigator versions 4.x and earlier. For info
on LiveConnect version 1, which was used in Navigator versions 3 and 4, and Enterprise
Server 3, see Netscape's
DevEdge site or any number of 3rd-party publications.)
-
-LiveConnect version 3 (10/31/98)
+ LiveConnect version 3 (8/31/99)
- In previous versions of LiveConnect, when more than one overloaded Java
@@ -115,7 +114,17 @@ LiveConnect version 3 (10/31/98)
a language feature that debuted in JavaScript 1.4. Now, when JavaScript
calls into Java, any Java exceptions are converted to JS exceptions which
can be caught using JS try-catch statements. Similarly, JS exceptions
- are propagated to Java wrapped in an instance of netscape.javascript.JSException.
+ are propagated to Java wrapped in an instance of netscape.javascript.JSException.
+
+
+ - JavaScript Array objects can now be passed to Java methods that expect a
+ Java array as an argument.
+ LiveConnect will create a new Java array of the appropriate type with a length
+ equal to that of the JS Array object. Each element of the Java array is filled
+ in by converting the corresponding element of the JS array, including undefined
+ elements, to an equivalent Java value. Note: Since the contents of the JS
+ array are copied, side-effects made by the invoked Java method to the Java
+ array will not be reflected in the JS array argument.
diff --git a/js/src/liveconnect/jsj.c b/js/src/liveconnect/jsj.c
index 45e2431e703..0ed147a7799 100644
--- a/js/src/liveconnect/jsj.c
+++ b/js/src/liveconnect/jsj.c
@@ -74,6 +74,7 @@ report_java_initialization_error(JNIEnv *jEnv, const char *js_error_msg)
jclass jlObject; /* java.lang.Object */
jclass jlrMethod; /* java.lang.reflect.Method */
jclass jlrField; /* java.lang.reflect.Field */
+jclass jlrArray; /* java.lang.reflect.Array */
jclass jlVoid; /* java.lang.Void */
jclass jlrConstructor; /* java.lang.reflect.Constructor */
jclass jlThrowable; /* java.lang.Throwable */
@@ -106,6 +107,8 @@ jmethodID jlrField_getName; /* java.lang.reflect.Field.getName() */
jmethodID jlrField_getType; /* java.lang.reflect.Field.getType() */
jmethodID jlrField_getModifiers; /* java.lang.reflect.Field.getModifiers() */
+jmethodID jlrArray_newInstance; /* java.lang.reflect.Array.newInstance() */
+
jmethodID jlBoolean_Boolean; /* java.lang.Boolean constructor */
jmethodID jlBoolean_booleanValue; /* java.lang.Boolean.booleanValue() */
jmethodID jlDouble_Double; /* java.lang.Double constructor */
@@ -229,6 +232,7 @@ init_java_VM_reflection(JSJavaVM *jsjava_vm, JNIEnv *jEnv)
LOAD_CLASS(java/lang/reflect/Method, jlrMethod);
LOAD_CLASS(java/lang/reflect/Constructor, jlrConstructor);
LOAD_CLASS(java/lang/reflect/Field, jlrField);
+ LOAD_CLASS(java/lang/reflect/Array, jlrArray);
LOAD_CLASS(java/lang/Throwable, jlThrowable);
LOAD_CLASS(java/lang/System, jlSystem);
LOAD_CLASS(java/lang/Boolean, jlBoolean);
@@ -256,6 +260,9 @@ init_java_VM_reflection(JSJavaVM *jsjava_vm, JNIEnv *jEnv)
LOAD_METHOD(java.lang.reflect.Field, getType, "()Ljava/lang/Class;", jlrField);
LOAD_METHOD(java.lang.reflect.Field, getModifiers, "()I", jlrField);
+ LOAD_STATIC_METHOD(java.lang.reflect.Array,
+ newInstance, "(Ljava/lang/Class;I)Ljava/lang/Object;",jlrArray);
+
LOAD_METHOD(java.lang.Throwable, toString, "()Ljava/lang/String;", jlThrowable);
LOAD_METHOD(java.lang.Throwable, getMessage, "()Ljava/lang/String;", jlThrowable);
@@ -555,6 +562,7 @@ JSJ_DisconnectFromJavaVM(JSJavaVM *jsjava_vm)
UNLOAD_CLASS(java/lang/reflect/Method, jlrMethod);
UNLOAD_CLASS(java/lang/reflect/Constructor, jlrConstructor);
UNLOAD_CLASS(java/lang/reflect/Field, jlrField);
+ UNLOAD_CLASS(java/lang/reflect/Array, jlrArray);
UNLOAD_CLASS(java/lang/Throwable, jlThrowable);
UNLOAD_CLASS(java/lang/System, jlSystem);
UNLOAD_CLASS(java/lang/Boolean, jlBoolean);
diff --git a/js/src/liveconnect/jsj_JSObject.c b/js/src/liveconnect/jsj_JSObject.c
index 630b0093c3f..66f2a9c6b3f 100644
--- a/js/src/liveconnect/jsj_JSObject.c
+++ b/js/src/liveconnect/jsj_JSObject.c
@@ -838,7 +838,7 @@ Java_netscape_javascript_JSObject_getMember(JNIEnv *jEnv,
property_name_ucs2 = NULL;
if (!property_name_jstr) {
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
- JSJMSG_NULL_MEMBER_NAME);
+ JSJMSG_NULL_MEMBER_NAME);
member = NULL;
goto done;
}
diff --git a/js/src/liveconnect/jsj_convert.c b/js/src/liveconnect/jsj_convert.c
index 9b10d685e95..652e0f3bca4 100644
--- a/js/src/liveconnect/jsj_convert.c
+++ b/js/src/liveconnect/jsj_convert.c
@@ -76,6 +76,54 @@ convert_js_obj_to_JSObject_wrapper(JSContext *cx, JNIEnv *jEnv, JSObject *js_obj
return (*java_value != NULL);
}
+/* Copy an array from JS to Java; Create a new Java array and populate its
+ elements, one by one, with the result of converting each JS array element
+ to the type of the array component. */
+static JSBool
+convert_js_array_to_java_array(JSContext *cx, JNIEnv *jEnv, JSObject *js_array,
+ JavaSignature *signature,
+ jobject *java_valuep)
+{
+ jsuint i;
+ jsval js_val;
+ jsuint length;
+ jclass component_class;
+ jarray java_array;
+ JavaSignature *array_component_signature;
+
+ if (!JS_GetArrayLength(cx, js_array, &length))
+ return JS_FALSE;
+
+ /* Get the Java class of each element of the array */
+ array_component_signature = signature->array_component_signature;
+ component_class = array_component_signature->java_class;
+
+ /* Create a new empty Java array with the same length as the JS array */
+ java_array = (*jEnv)->CallStaticObjectMethod(jEnv, jlrArray, jlrArray_newInstance,
+ component_class, length);
+ if (!java_array) {
+ jsj_ReportJavaError(cx, jEnv, "Error while constructing empty array of %s",
+ jsj_GetJavaClassName(cx, jEnv, component_class));
+ return JS_FALSE;
+ }
+
+ /* Convert each element of the JS array to an element of the Java array.
+ If an error occurs, there is no need to worry about releasing the
+ individual elements of the Java array - they will eventually be GC'ed
+ by the JVM. */
+ for (i = 0; i < length; i++) {
+ if (!JS_LookupElement(cx, js_array, i, &js_val))
+ return JS_FALSE;
+
+ if (!jsj_SetJavaArrayElement(cx, jEnv, java_array, i, array_component_signature, js_val))
+ return JS_FALSE;
+ }
+
+ /* Return the result array */
+ *java_valuep = java_array;
+ return JS_TRUE;
+}
+
jstring
jsj_ConvertJSStringToJavaString(JSContext *cx, JNIEnv *jEnv, JSString *js_str)
{
@@ -169,6 +217,15 @@ jsj_ConvertJSValueToJavaObject(JSContext *cx, JNIEnv *jEnv, jsval v, JavaSignatu
return jsj_ConvertJSValueToJavaObject(cx, jEnv, v, signature, cost,
java_value, is_local_refp);
+ /* JS Arrays are converted, element by element, to Java arrays */
+ } else if (JS_IsArrayObject(cx, js_obj) && (signature->type == JAVA_SIGNATURE_ARRAY)) {
+ if (convert_js_array_to_java_array(cx, jEnv, js_obj, signature, java_value)) {
+ if (java_value && *java_value)
+ *is_local_refp = JS_TRUE;
+ return JS_TRUE;
+ }
+ return JS_FALSE;
+
} else {
/* Otherwise, see if the target type is the netscape.javascript.JSObject
wrapper class or one of its subclasses, in which case a
@@ -227,7 +284,9 @@ jsj_ConvertJSValueToJavaObject(JSContext *cx, JNIEnv *jEnv, jsval v, JavaSignatu
/* Fall through, to attempt conversion to a java.lang.String ... */
}
- /* If no other conversion is possible, see if the target type is java.lang.String */
+ /* If the source JS type is either a string or undefined, or if no conversion
+ is possible from a number, boolean or JS object, see if the target type is
+ java.lang.String */
if ((*jEnv)->IsAssignableFrom(jEnv, jlString, target_java_class)) {
/* Convert to JS string, if necessary, and then to a Java Unicode string */
@@ -503,6 +562,7 @@ conversion_error:
if (java_value) {
const char *jsval_string;
+ const char *class_name;
JSString *jsstr;
jsval_string = NULL;
@@ -512,8 +572,11 @@ conversion_error:
if (!jsval_string)
jsval_string = "";
+ class_name = jsj_ConvertJavaSignatureToHRString(cx, signature);
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
- JSJMSG_CANT_CONVERT_JS, jsval_string, signature->name);
+ JSJMSG_CANT_CONVERT_JS, jsval_string,
+ class_name);
+
return JS_FALSE;
}
return success;
diff --git a/js/src/liveconnect/jsj_method.c b/js/src/liveconnect/jsj_method.c
index e3d413c9131..25dfacced88 100644
--- a/js/src/liveconnect/jsj_method.c
+++ b/js/src/liveconnect/jsj_method.c
@@ -65,6 +65,7 @@ typedef enum JSJType {
JSJTYPE_JAVACLASS, /* JavaClass */
JSJTYPE_JAVAOBJECT, /* JavaObject */
JSJTYPE_JAVAARRAY, /* JavaArray */
+ JSJTYPE_JSARRAY, /* JS Array */
JSJTYPE_OBJECT, /* Any other JS Object, including functions */
JSJTYPE_LIMIT
} JSJType;
@@ -939,6 +940,8 @@ compute_jsj_type(JSContext *cx, jsval v)
return JSJTYPE_JAVAARRAY;
if (JS_InstanceOf(cx, js_obj, &JavaClass_class, 0))
return JSJTYPE_JAVACLASS;
+ if (JS_IsArrayObject(cx, js_obj))
+ return JSJTYPE_JSARRAY;
return JSJTYPE_OBJECT;
} else if (JSVAL_IS_NUMBER(v)) {
return JSJTYPE_NUMBER;
@@ -978,7 +981,8 @@ static int rank_table[JSJTYPE_LIMIT][JAVA_SIGNATURE_LIMIT] = {
{99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 1, 99, 2, 3, 4}, /* JavaClass */
{99, 7, 8, 6, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 0, 1}, /* JavaObject */
{99, 99, 99, 99, 99, 99, 99, 99, 0, 0, 99, 99, 99, 99, 0, 1}, /* JavaArray */
- {99, 9, 10, 8, 7, 6, 5, 4, 99, 99, 99, 99, 99, 1, 2, 3}, /* other JS object */
+ {99, 99, 99, 99, 99, 99, 99, 99, 2, 99, 99, 99, 99, 1, 3, 4}, /* JS Array */
+ {99, 9, 10, 8, 7, 6, 5, 4, 99, 99, 99, 99, 99, 1, 2, 3} /* other JS object */
};
/*
diff --git a/js/src/liveconnect/jsj_private.h b/js/src/liveconnect/jsj_private.h
index 2e74d02612a..3d1d9f58fc5 100644
--- a/js/src/liveconnect/jsj_private.h
+++ b/js/src/liveconnect/jsj_private.h
@@ -248,6 +248,7 @@ extern JSClass JavaMember_class;
*/
extern jclass jlObject; /* java.lang.Object */
extern jclass jlrConstructor; /* java.lang.reflect.Constructor */
+extern jclass jlrArray; /* java.lang.reflect.Array */
extern jclass jlThrowable; /* java.lang.Throwable */
extern jclass jlSystem; /* java.lang.System */
extern jclass jlClass; /* java.lang.Class */
@@ -278,6 +279,8 @@ extern jmethodID jlrField_getName; /* java.lang.reflect.Field.getNam
extern jmethodID jlrField_getType; /* java.lang.reflect.Field.getType() */
extern jmethodID jlrField_getModifiers; /* java.lang.reflect.Field.getModifiers() */
+extern jmethodID jlrArray_newInstance; /* java.lang.reflect.Array.newInstance() */
+
extern jmethodID jlThrowable_getMessage; /* java.lang.Throwable.getMessage() */
extern jmethodID jlThrowable_toString; /* java.lang.Throwable.toString() */