v8::Handle<v8::Value> TypeConverter::javaObjectToJsValue(JNIEnv *env, jobject javaObject) { if (!javaObject) { return v8::Null(); } if (env->IsInstanceOf(javaObject, JNIUtil::booleanClass)) { jboolean javaBoolean = env->CallBooleanMethod(javaObject, JNIUtil::booleanBooleanValueMethod); return javaBoolean ? v8::True() : v8::False(); } else if (env->IsInstanceOf(javaObject, JNIUtil::numberClass)) { jdouble javaDouble = env->CallDoubleMethod(javaObject, JNIUtil::numberDoubleValueMethod); return v8::Number::New((double) javaDouble); } else if (env->IsInstanceOf(javaObject, JNIUtil::stringClass)) { return TypeConverter::javaStringToJsString(env, (jstring) javaObject); } else if (env->IsInstanceOf(javaObject, JNIUtil::dateClass)) { return TypeConverter::javaDateToJsDate(env, javaObject); } else if (env->IsInstanceOf(javaObject, JNIUtil::hashMapClass)) { return TypeConverter::javaHashMapToJsValue(env, javaObject); } else if (env->IsInstanceOf(javaObject, JNIUtil::krollProxyClass)) { jobject krollObject = env->GetObjectField(javaObject, JNIUtil::krollProxyKrollObjectField); if (krollObject) { jlong v8ObjectPointer = env->GetLongField(krollObject, JNIUtil::v8ObjectPtrField); env->DeleteLocalRef(krollObject); if (v8ObjectPointer != 0) { Persistent<Object> v8Object = Persistent<Object>((Object *) v8ObjectPointer); JavaObject *jo = NativeObject::Unwrap<JavaObject>(v8Object); jobject javaProxy = jo->getJavaObject(); // Called to explicitly go from weak reference to strong! if (!JavaObject::useGlobalRefs) { // But then we need to delete the local reference to avoid JNI ref leak! env->DeleteLocalRef(javaProxy); } return v8Object; } } jclass javaObjectClass = env->GetObjectClass(javaObject); v8::Handle<v8::Object> proxyHandle = ProxyFactory::createV8Proxy(javaObjectClass, javaObject); env->DeleteLocalRef(javaObjectClass); return proxyHandle; } else if (env->IsInstanceOf(javaObject, JNIUtil::v8FunctionClass)) { return javaObjectToJsFunction(javaObject); } else if (env->IsInstanceOf(javaObject, JNIUtil::objectArrayClass)) { return javaArrayToJsArray((jobjectArray) javaObject); } else if (env->IsInstanceOf(javaObject, JNIUtil::shortArrayClass)) { return javaArrayToJsArray((jshortArray) javaObject); } else if (env->IsInstanceOf(javaObject, JNIUtil::intArrayClass)) { return javaArrayToJsArray((jintArray) javaObject); } else if (env->IsInstanceOf(javaObject, JNIUtil::longArrayClass)) { return javaArrayToJsArray((jlongArray) javaObject); } else if (env->IsInstanceOf(javaObject, JNIUtil::floatArrayClass)) { return javaArrayToJsArray((jfloatArray) javaObject); } else if (env->IsInstanceOf(javaObject, JNIUtil::doubleArrayClass)) { return javaArrayToJsArray((jdoubleArray) javaObject); } else if (env->IsInstanceOf(javaObject, JNIUtil::booleanArrayClass)) { return javaArrayToJsArray((jbooleanArray) javaObject); } else if (env->IsSameObject(JNIUtil::undefinedObject, javaObject)) { return v8::Undefined(); } jclass javaObjectClass = env->GetObjectClass(javaObject); JNIUtil::logClassName("!!! Unable to convert unknown Java object class '%s' to JS value !!!", javaObjectClass, true); env->DeleteLocalRef(javaObjectClass); return v8::Handle<v8::Value>(); }
// converts js value to java object and recursively converts sub objects if this // object is a container type jobject TypeConverter::jsValueToJavaObject(v8::Local<v8::Value> jsValue, bool *isNew) { JNIEnv *env = JNIScope::getEnv(); if (env == NULL) { return NULL; } if (jsValue->IsNumber()) { jdouble javaDouble = TypeConverter::jsNumberToJavaDouble(jsValue->ToNumber()); *isNew = true; return env->NewObject(JNIUtil::doubleClass, JNIUtil::doubleInitMethod, javaDouble); } else if (jsValue->IsBoolean()) { jboolean javaBoolean = TypeConverter::jsBooleanToJavaBoolean(jsValue->ToBoolean()); *isNew = true; return env->NewObject(JNIUtil::booleanClass, JNIUtil::booleanInitMethod, javaBoolean); } else if (jsValue->IsString()) { *isNew = true; return TypeConverter::jsStringToJavaString(jsValue->ToString()); } else if (jsValue->IsDate()) { Local<Date> date = Local<Date>::Cast<Value>(jsValue); return TypeConverter::jsDateToJavaDate(date); } else if (jsValue->IsArray()) { *isNew = true; return TypeConverter::jsArrayToJavaArray(v8::Handle<v8::Array>::Cast(jsValue)); } else if (jsValue->IsFunction()) { *isNew = true; return TypeConverter::jsObjectToJavaFunction(jsValue->ToObject()); } else if (jsValue->IsObject()) { v8::Handle<v8::Object> jsObject = jsValue->ToObject(); if (JavaObject::isJavaObject(jsObject)) { *isNew = JavaObject::useGlobalRefs ? false : true; JavaObject *javaObject = JavaObject::Unwrap<JavaObject>(jsObject); return javaObject->getJavaObject(); } else { v8::Handle<v8::Array> objectKeys = jsObject->GetOwnPropertyNames(); int numKeys = objectKeys->Length(); *isNew = true; jobject javaHashMap = env->NewObject(JNIUtil::hashMapClass, JNIUtil::hashMapInitMethod, numKeys); for (int i = 0; i < numKeys; i++) { v8::Local<v8::Value> jsObjectPropertyKey = objectKeys->Get((uint32_t) i); bool keyIsNew, valueIsNew; jobject javaObjectPropertyKey = TypeConverter::jsValueToJavaObject(jsObjectPropertyKey, &keyIsNew); v8::Local<v8::Value> jsObjectPropertyValue = jsObject->Get(jsObjectPropertyKey); jobject javaObjectPropertyValue = TypeConverter::jsValueToJavaObject(jsObjectPropertyValue, &valueIsNew); jobject result = env->CallObjectMethod(javaHashMap, JNIUtil::hashMapPutMethod, javaObjectPropertyKey, javaObjectPropertyValue); env->DeleteLocalRef(result); if (keyIsNew) { env->DeleteLocalRef(javaObjectPropertyKey); } if (valueIsNew) { env->DeleteLocalRef(javaObjectPropertyValue); } } return javaHashMap; } } LOGW(TAG, "jsValueToJavaObject returning null"); return NULL; }
jobject TypeConverter::jsValueToJavaObject(JNIEnv *env, v8::Local<v8::Value> jsValue, bool *isNew) { if (jsValue->IsNumber()) { *isNew = true; if (jsValue->IsInt32()) { jint javaInt = TypeConverter::jsNumberToJavaInt(jsValue->ToNumber()); return env->NewObject(JNIUtil::integerClass, JNIUtil::integerInitMethod, javaInt); } jdouble javaDouble = TypeConverter::jsNumberToJavaDouble(jsValue->ToNumber()); return env->NewObject(JNIUtil::doubleClass, JNIUtil::doubleInitMethod, javaDouble); } else if (jsValue->IsBoolean()) { jboolean javaBoolean = TypeConverter::jsBooleanToJavaBoolean(jsValue->ToBoolean()); *isNew = true; return env->NewObject(JNIUtil::booleanClass, JNIUtil::booleanInitMethod, javaBoolean); } else if (jsValue->IsString()) { *isNew = true; return TypeConverter::jsStringToJavaString(env, jsValue->ToString()); } else if (jsValue->IsDate()) { Local<Date> date = Local<Date>::Cast<Value>(jsValue); return TypeConverter::jsDateToJavaDate(env, date); } else if (jsValue->IsArray()) { *isNew = true; return TypeConverter::jsArrayToJavaArray(env, v8::Handle<v8::Array>::Cast(jsValue)); } else if (jsValue->IsFunction()) { *isNew = true; return TypeConverter::jsObjectToJavaFunction(env, jsValue->ToObject()); } else if (jsValue->IsObject()) { v8::Handle<v8::Object> jsObject = jsValue->ToObject(); if (JavaObject::isJavaObject(jsObject)) { *isNew = JavaObject::useGlobalRefs ? false : true; JavaObject *javaObject = JavaObject::Unwrap<JavaObject>(jsObject); return javaObject->getJavaObject(); } else { // Unwrap hyperloop JS wrappers to get native java proxy Handle<String> nativeString = String::New("$native"); if (jsObject->HasOwnProperty(nativeString)) { v8::Local<v8::Value> nativeObject = jsObject->GetRealNamedProperty(nativeString); jsObject = nativeObject->ToObject(); if (JavaObject::isJavaObject(jsObject)) { *isNew = JavaObject::useGlobalRefs ? false : true; JavaObject *javaObject = JavaObject::Unwrap<JavaObject>(jsObject); return javaObject->getJavaObject(); } } v8::Handle<v8::Array> objectKeys = jsObject->GetOwnPropertyNames(); int numKeys = objectKeys->Length(); *isNew = true; jobject javaHashMap = env->NewObject(JNIUtil::hashMapClass, JNIUtil::hashMapInitMethod, numKeys); for (int i = 0; i < numKeys; i++) { v8::Local<v8::Value> jsObjectPropertyKey = objectKeys->Get((uint32_t) i); bool keyIsNew, valueIsNew; jobject javaObjectPropertyKey = TypeConverter::jsValueToJavaObject(env, jsObjectPropertyKey, &keyIsNew); v8::Local<v8::Value> jsObjectPropertyValue = jsObject->Get(jsObjectPropertyKey); jobject javaObjectPropertyValue = TypeConverter::jsValueToJavaObject(env, jsObjectPropertyValue, &valueIsNew); jobject result = env->CallObjectMethod(javaHashMap, JNIUtil::hashMapPutMethod, javaObjectPropertyKey, javaObjectPropertyValue); env->DeleteLocalRef(result); if (keyIsNew) { env->DeleteLocalRef(javaObjectPropertyKey); } if (valueIsNew) { env->DeleteLocalRef(javaObjectPropertyValue); } } return javaHashMap; } } if (!jsValue->IsNull() && !jsValue->IsUndefined()) { LOGW(TAG, "jsValueToJavaObject returning null."); } return NULL; }