예제 #1
0
/*
 * Convert a Java value (primitive or object) to a JS value.
 *
 * This is usually an infallible operation, but JS_FALSE is returned
 * on an out-of-memory condition and the error reporter is called.
 */
JSBool
jsj_ConvertJavaValueToJSValue(JSContext *cx, JNIEnv *jEnv,
                              JavaSignature *signature,
                              jvalue *java_value,
                              jsval *vp)
{
    int32 ival32;

    switch (signature->type) {
    case JAVA_SIGNATURE_VOID:
        *vp = JSVAL_VOID;
        return JS_TRUE;

    case JAVA_SIGNATURE_BYTE:
        *vp = INT_TO_JSVAL((jsint)java_value->b);
        return JS_TRUE;

    case JAVA_SIGNATURE_CHAR:
        *vp = INT_TO_JSVAL((jsint)java_value->c);
        return JS_TRUE;

    case JAVA_SIGNATURE_SHORT:
        *vp = INT_TO_JSVAL((jsint)java_value->s);
        return JS_TRUE;

    case JAVA_SIGNATURE_INT:
        ival32 = java_value->i;
        if (INT_FITS_IN_JSVAL(ival32)) {
            *vp = INT_TO_JSVAL((jsint) ival32);
            return JS_TRUE;
        } else {
            return JS_NewDoubleValue(cx, ival32, vp);
        }

    case JAVA_SIGNATURE_BOOLEAN:
        *vp = BOOLEAN_TO_JSVAL((JSBool) java_value->z);
        return JS_TRUE;

    case JAVA_SIGNATURE_LONG:
        return JS_NewDoubleValue(cx, jlong_to_jdouble(java_value->j), vp);
  
    case JAVA_SIGNATURE_FLOAT:
        return JS_NewDoubleValue(cx, java_value->f, vp);

    case JAVA_SIGNATURE_DOUBLE:
        return JS_NewDoubleValue(cx, java_value->d, vp);

    case JAVA_SIGNATURE_UNKNOWN:
        JS_ASSERT(0);
        return JS_FALSE;
        
    /* Non-primitive (reference) type */
    default:
        JS_ASSERT(IS_REFERENCE_TYPE(signature->type));
        return jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_value->l, vp);

    }
}
예제 #2
0
/*
 * Convert a JS value to a Java value of the given type signature.  The cost
 * variable is incremented if coercion is required, e.g. the source value is
 * a string, but the target type is a boolean.
 *
 * Returns JS_FALSE if no conversion is possible, either because the jsval has
 * a type that is wholly incompatible with the Java value, or because a scalar
 * jsval can't be represented in a variable of the target type without loss of
 * precision, e.g. the source value is "4.2" but the destination type is byte.
 * If conversion is not possible and java_value is non-NULL, the JS error
 * reporter is called with an appropriate message.
 */  
JSBool
jsj_ConvertJSValueToJavaValue(JSContext *cx, JNIEnv *jEnv, jsval v_arg,
                              JavaSignature *signature,
                              int *cost, jvalue *java_value, JSBool *is_local_refp)
{
    JavaSignatureChar type;
    jsval v;
    JSBool success = JS_FALSE;

    /* Initialize to default case, in which no new Java object is
       synthesized to perform the conversion and, therefore, no JNI local
       references are being held. */
    *is_local_refp = JS_FALSE;   
    
    type = signature->type;
    v = v_arg;
    switch (type) {
    case JAVA_SIGNATURE_BOOLEAN:
        if (!JSVAL_IS_BOOLEAN(v)) {
            if (!JS_ConvertValue(cx, v, JSTYPE_BOOLEAN, &v))
                goto conversion_error;
            if (JSVAL_IS_VOID(v))
                goto conversion_error;
            (*cost)++;
        }
        if (java_value)
            java_value->z = (jboolean)(JSVAL_TO_BOOLEAN(v) == JS_TRUE);
        break;

    case JAVA_SIGNATURE_SHORT:
        JSVAL_TO_INTEGRAL_JVALUE(short, s, jshort, v, java_value);
        break;

    case JAVA_SIGNATURE_BYTE:
        JSVAL_TO_INTEGRAL_JVALUE(byte, b, jbyte, v, java_value);
        break;

    case JAVA_SIGNATURE_CHAR:
        /* A one-character string can be converted into a character */
        if (JSVAL_IS_STRING(v) && (JS_GetStringLength(JSVAL_TO_STRING(v)) == 1)) {
            v = INT_TO_JSVAL(*JS_GetStringChars(JSVAL_TO_STRING(v)));
        }
        JSVAL_TO_INTEGRAL_JVALUE(char, c, jchar, v, java_value);
        break;

    case JAVA_SIGNATURE_INT:
        JSVAL_TO_INTEGRAL_JVALUE(int, i, jint, v, java_value);
        break;

    case JAVA_SIGNATURE_LONG:
#if defined(XP_MAC) || (defined(XP_OS2) && !defined(HAVE_LONG_LONG))
        JSVAL_TO_JLONG_JVALUE(j, jlong, v, java_value);
#else
        JSVAL_TO_INTEGRAL_JVALUE(long, j, jlong, v, java_value);
#endif
        break;
    
    case JAVA_SIGNATURE_FLOAT:
        if (!JSVAL_IS_NUMBER(v)) {
            if (!JS_ConvertValue(cx, v, JSTYPE_NUMBER, &v))
                goto conversion_error;
            (*cost)++;
        }
        if (java_value) {
            if (JSVAL_IS_INT(v))
                java_value->f = (jfloat) JSVAL_TO_INT(v);
            else
                java_value->f = (jfloat) *JSVAL_TO_DOUBLE(v);
        }
        break;

    case JAVA_SIGNATURE_DOUBLE:
        if (!JSVAL_IS_NUMBER(v)) {
            if (!JS_ConvertValue(cx, v, JSTYPE_NUMBER, &v))
                goto conversion_error;
            (*cost)++;
        }
        if (java_value) {
            if (JSVAL_IS_INT(v))
                java_value->d = (jdouble) JSVAL_TO_INT(v);
            else
                java_value->d = (jdouble) *JSVAL_TO_DOUBLE(v);
        }
        break;

    /* Non-primitive (reference) type */
    default:
        JS_ASSERT(IS_REFERENCE_TYPE(type));
        if (!jsj_ConvertJSValueToJavaObject(cx, jEnv, v, signature, cost,
            &java_value->l, is_local_refp))
            goto conversion_error;
        break;

    case JAVA_SIGNATURE_UNKNOWN:
    case JAVA_SIGNATURE_VOID:
        JS_ASSERT(0);
        return JS_FALSE;
    }

    /* Success */
    return JS_TRUE;

numeric_conversion_error:
    success = JS_TRUE;
    /* Fall through ... */

conversion_error:

    if (java_value) {
        const char *jsval_string;
        const char *class_name;
        JSString *jsstr;

        jsval_string = NULL;
        jsstr = JS_ValueToString(cx, v_arg);
        if (jsstr)
            jsval_string = JS_GetStringBytes(jsstr);
        if (!jsval_string)
            jsval_string = "";
        
        class_name = jsj_ConvertJavaSignatureToHRString(cx, signature);
        JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, 
                             JSJMSG_CANT_CONVERT_JS, jsval_string,
                             class_name);

        return JS_FALSE;
    }
    return success;
}
예제 #3
0
JSBool
jsj_SetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec,
                      jclass java_obj, jsval js_val)
{
    JSBool is_static_field, is_local_ref;
    int dummy_cost;
    jvalue java_value;
    JavaSignature *signature;
    JavaSignatureChar field_type;
    jfieldID fieldID = field_spec->fieldID;

    is_static_field = field_spec->modifiers & ACC_STATIC;

#define SET_JAVA_FIELD(Type,member)                                          \
    JS_BEGIN_MACRO                                                           \
    if (is_static_field) {                                                   \
        (*jEnv)->SetStatic##Type##Field(jEnv, java_obj, fieldID,             \
                                        java_value.member);                  \
    } else {                                                                 \
        (*jEnv)->Set##Type##Field(jEnv, java_obj, fieldID,java_value.member);\
    }                                                                        \
    if ((*jEnv)->ExceptionOccurred(jEnv)) {                                  \
        jsj_UnexpectedJavaError(cx, jEnv, "Error assigning to Java field");      \
        return JS_FALSE;                                                     \
    }                                                                        \
    JS_END_MACRO

    signature = field_spec->signature;
    if (!jsj_ConvertJSValueToJavaValue(cx, jEnv, js_val, signature, &dummy_cost,
                                       &java_value, &is_local_ref))
        return JS_FALSE;

    field_type = signature->type;
    switch(field_type) {
    case JAVA_SIGNATURE_BYTE:
        SET_JAVA_FIELD(Byte,b);
        break;

    case JAVA_SIGNATURE_CHAR:
        SET_JAVA_FIELD(Char,c);
        break;

    case JAVA_SIGNATURE_SHORT:
        SET_JAVA_FIELD(Short,s);
        break;

    case JAVA_SIGNATURE_INT:
        SET_JAVA_FIELD(Int,i);
        break;

    case JAVA_SIGNATURE_BOOLEAN:
        SET_JAVA_FIELD(Boolean,z);
        break;

    case JAVA_SIGNATURE_LONG:
        SET_JAVA_FIELD(Long,j);
        break;

    case JAVA_SIGNATURE_FLOAT:
        SET_JAVA_FIELD(Float,f);
        break;

    case JAVA_SIGNATURE_DOUBLE:
        SET_JAVA_FIELD(Double,d);
        break;

    /* Non-primitive (reference) type */
    default:
        JS_ASSERT(IS_REFERENCE_TYPE(field_type));
        SET_JAVA_FIELD(Object,l);
        if (is_local_ref)
            (*jEnv)->DeleteLocalRef(jEnv, java_value.l);
        break;

    case JAVA_SIGNATURE_UNKNOWN:
    case JAVA_SIGNATURE_VOID:
        JS_ASSERT(0);        /* Unknown java type signature */
        return JS_FALSE;
    }

#undef SET_JAVA_FIELD

    return JS_TRUE;
}
예제 #4
0
/*
 * Convert a JS value to an instance of java.lang.Object or one of its subclasses, 
 * performing any necessary type coercion.  If non-trivial coercion is required,
 * the cost value is incremented.  If the java_value pass-by-reference argument
 * is non-NULL, the resulting Java value is stored there.
 *
 * Returns JS_TRUE if the conversion is possible, JS_FALSE otherwise
 */
JSBool
jsj_ConvertJSValueToJavaObject(JSContext *cx, JNIEnv *jEnv, jsval v, JavaSignature *signature,
                               int *cost, jobject *java_value, JSBool *is_local_refp)
{
    JSString *jsstr;
    jclass target_java_class;
    
    JS_ASSERT(IS_REFERENCE_TYPE(signature->type));

    /* Initialize to default case, in which no new Java object is
       synthesized to perform the conversion and, therefore, no JNI local
       references are being held. */
    *is_local_refp = JS_FALSE;

    /* Get the Java type of the target value */
    target_java_class = signature->java_class;
    
    if (JSVAL_IS_OBJECT(v)) {
        JSObject *js_obj = JSVAL_TO_OBJECT(v);
        
        /* JS null is always assignable to a Java object */
        if (!js_obj) {
            if (java_value)
                *java_value = NULL;
            return JS_TRUE;
        }
        
        if (JS_InstanceOf(cx, js_obj, &JavaObject_class, 0) ||
            JS_InstanceOf(cx, js_obj, &JavaArray_class, 0)) {
            
            /* The source value is a Java object wrapped inside a JavaScript
               object.  Unwrap the JS object and return the original Java
               object if it's class makes it assignment-compatible with the
               target class using Java's assignability rules. */
            JavaObjectWrapper *java_wrapper = JS_GetPrivate(cx, js_obj);
            jobject java_obj = java_wrapper->java_obj;
            
            if ((*jEnv)->IsInstanceOf(jEnv, java_obj, target_java_class)) {
                if (java_value)
                    *java_value = java_obj;
                return JS_TRUE;
            }
            
            /* Fall through, to attempt conversion to a Java string */
            
        } else if (JS_InstanceOf(cx, js_obj, &JavaClass_class, 0)) {
            /* We're dealing with the reflection of a Java class */
            JavaClassDescriptor *java_class_descriptor = JS_GetPrivate(cx, js_obj);
            
            /* Check if target type is java.lang.Class class */
            if ((*jEnv)->IsAssignableFrom(jEnv, jlClass, target_java_class)) {
                if (java_value)
                    *java_value = java_class_descriptor->java_class;
                return JS_TRUE;
            }
            
            /* Check if target type is netscape.javascript.JSObject wrapper class */
            if (convert_js_obj_to_JSObject_wrapper(cx, jEnv, js_obj, signature, cost, java_value)) {
                if (java_value && *java_value)
                    *is_local_refp = JS_TRUE;
                return JS_TRUE;
            }
            
            /* Fall through, to attempt conversion to a Java string */
            
        } else if (JS_InstanceOf(cx, js_obj, &JavaMember_class, 0)) {

            if (!JS_ConvertValue(cx, v, JSTYPE_OBJECT, &v))
                return JS_FALSE;
            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
               reference is passed to the original JS object by wrapping it
               inside an instance of netscape.javascript.JSObject */
            if (convert_js_obj_to_JSObject_wrapper(cx, jEnv, js_obj, signature, cost, java_value))             {
                if (java_value && *java_value)
                    *is_local_refp = JS_TRUE;
                return JS_TRUE;
            }
            
            /* Fall through, to attempt conversion to a Java string */
        }
        
    } else if (JSVAL_IS_NUMBER(v)) {
        /* JS numbers, integral or not, can be converted to instances of java.lang.Double */
        if ((*jEnv)->IsAssignableFrom(jEnv, jlDouble, target_java_class)) {
            if (java_value) {
                jsdouble d;
                if (!JS_ValueToNumber(cx, v, &d))
                    goto conversion_error;
                *java_value = (*jEnv)->NewObject(jEnv, jlDouble, jlDouble_Double, d);
                if (*java_value) {
                    *is_local_refp = JS_TRUE;
                } else {
                    jsj_UnexpectedJavaError(cx, jEnv,
                        "Couldn't construct instance of java.lang.Double");
                    return JS_FALSE;
                }
            }

            return JS_TRUE;
        }
        /* Fall through, to attempt conversion to a java.lang.String ... */
        
    } else if (JSVAL_IS_BOOLEAN(v)) {
        /* JS boolean values can be converted to instances of java.lang.Boolean */
        if ((*jEnv)->IsAssignableFrom(jEnv, jlBoolean, target_java_class)) {
            if (java_value) {
                JSBool b;
                if (!JS_ValueToBoolean(cx, v, &b))
                    goto conversion_error;
                *java_value =
                    (*jEnv)->NewObject(jEnv, jlBoolean, jlBoolean_Boolean, b);
                if (*java_value) {
                    *is_local_refp = JS_TRUE;
                } else {
                    jsj_UnexpectedJavaError(cx, jEnv, "Couldn't construct instance " 
                        "of java.lang.Boolean");
                    return JS_FALSE;
                }
            }

            return JS_TRUE;
        }
        /* Fall through, to attempt conversion to a 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 */
        jsstr = JS_ValueToString(cx, v);
        if (jsstr) {
            if (java_value) {
                *java_value = jsj_ConvertJSStringToJavaString(cx, jEnv, jsstr);
                if (*java_value) {
                    *is_local_refp = JS_TRUE;
                } else {
                    return JS_FALSE;
                }
            }

            return JS_TRUE;
        }
    }
    
conversion_error:
    return JS_FALSE;
}
예제 #5
0
/*
 * Read the value of a Java field and return it as a JavaScript value.
 * If the field is static, then java_obj is a Java class, otherwise
 * it's a Java instance object.
 *
 * Returns JS_TRUE on success. Otherwise, returns JS_FALSE and reports an error.
 */
JSBool
jsj_GetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec,
                      jobject java_obj, jsval *vp)
{
    JSBool is_static_field, success;
    jvalue java_value;
    JavaSignature *signature;
    JavaSignatureChar field_type;
    jfieldID fieldID = field_spec->fieldID;

    is_static_field = field_spec->modifiers & ACC_STATIC;

#define GET_JAVA_FIELD(Type,member)                                          \
    JS_BEGIN_MACRO                                                           \
    if (is_static_field)                                                     \
        java_value.member =                                                  \
            (*jEnv)->GetStatic##Type##Field(jEnv, (*jEnv)->GetObjectClass(jEnv, java_obj), fieldID);        \
    else                                                                     \
        java_value.member =                                                  \
            (*jEnv)->Get##Type##Field(jEnv, java_obj, fieldID);              \
    if ((*jEnv)->ExceptionOccurred(jEnv)) {                                  \
        jsj_UnexpectedJavaError(cx, jEnv, "Error reading Java field");           \
        return JS_FALSE;                                                     \
    }                                                                        \
    JS_END_MACRO

    signature = field_spec->signature;
    field_type = signature->type;
    switch(field_type) {
    case JAVA_SIGNATURE_BYTE:
        GET_JAVA_FIELD(Byte,b);
        break;

    case JAVA_SIGNATURE_CHAR:
        GET_JAVA_FIELD(Char,c);
        break;

    case JAVA_SIGNATURE_SHORT:
        GET_JAVA_FIELD(Short,s);
        break;

    case JAVA_SIGNATURE_INT:
        GET_JAVA_FIELD(Int,i);
        break;

    case JAVA_SIGNATURE_BOOLEAN:
        GET_JAVA_FIELD(Boolean,z);
        break;

    case JAVA_SIGNATURE_LONG:
        GET_JAVA_FIELD(Long,j);
        break;

    case JAVA_SIGNATURE_FLOAT:
        GET_JAVA_FIELD(Float,f);
        break;

    case JAVA_SIGNATURE_DOUBLE:
        GET_JAVA_FIELD(Double,d);
        break;

    case JAVA_SIGNATURE_UNKNOWN:
    case JAVA_SIGNATURE_VOID:
        JS_ASSERT(0);        /* Unknown java type signature */
        return JS_FALSE;

    /* Non-primitive (reference) type */
    default:
        JS_ASSERT(IS_REFERENCE_TYPE(field_type));
        GET_JAVA_FIELD(Object,l);
        success = jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_value.l, vp);
        (*jEnv)->DeleteLocalRef(jEnv, java_value.l);
        return success;
    }

#undef GET_JAVA_FIELD

    return jsj_ConvertJavaValueToJSValue(cx, jEnv, signature, &java_value, vp);
}