/*static*/ void JavaObject::fieldSetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo& info) { v8::HandleScope scope; JavaObject* self = node::ObjectWrap::Unwrap<JavaObject>(info.This()); JNIEnv *env = self->m_java->getJavaEnv(); JavaScope javaScope(env); jobject newValue = v8ToJava(env, value); v8::String::AsciiValue propertyCStr(property); std::string propertyStr = *propertyCStr; jobject field = javaFindField(env, self->m_class, propertyStr); if(field == NULL) { std::ostringstream errStr; errStr << "Could not find field " << propertyStr; v8::Handle<v8::Value> ex = javaExceptionToV8(env, errStr.str()); ThrowException(ex); return; } jclass fieldClazz = env->FindClass("java/lang/reflect/Field"); jmethodID field_set = env->GetMethodID(fieldClazz, "set", "(Ljava/lang/Object;Ljava/lang/Object;)V"); //printf("newValue: %s\n", javaObjectToString(env, newValue).c_str()); // set field value env->CallObjectMethod(field, field_set, self->m_obj, newValue); if(env->ExceptionOccurred()) { std::ostringstream errStr; errStr << "Could not set field " << propertyStr; v8::Handle<v8::Value> ex = javaExceptionToV8(env, errStr.str()); ThrowException(ex); return; } }
jobject v8ToJava_javaLong(JNIEnv* env, v8::Local<v8::Object> obj) { jobject longValue = v8ToJava(env, obj->Get(v8::String::New("longValue"))); jclass longClazz = env->FindClass("java/lang/Long"); jmethodID long_constructor = env->GetMethodID(longClazz, "<init>", "(Ljava/lang/String;)V"); jobject jobj = env->NewObject(longClazz, long_constructor, longValue); return jobj; }
/*static*/ v8::Handle<v8::Value> JavaObject::methodCallSync(const v8::Arguments& args) { v8::HandleScope scope; JavaObject* self = node::ObjectWrap::Unwrap<JavaObject>(args.This()); JNIEnv *env = self->m_java->getJavaEnv(); JavaScope javaScope(env); v8::String::AsciiValue methodName(args.Data()); std::string methodNameStr = *methodName; int argsStart = 0; int argsEnd = args.Length(); jobjectArray methodArgs = v8ToJava(env, args, argsStart, argsEnd); jobject method = javaFindMethod(env, self->m_class, methodNameStr, methodArgs); if(method == NULL) { std::string msg = methodNotFoundToString(env, self->m_class, methodNameStr, false, args, argsStart, argsEnd); v8::Handle<v8::Value> ex = javaExceptionToV8(env, msg); return ThrowException(ex); } // run v8::Handle<v8::Value> callback = v8::Undefined(); InstanceMethodCallBaton* baton = new InstanceMethodCallBaton(self->m_java, self, method, methodArgs, callback); v8::Handle<v8::Value> result = baton->runSync(); delete baton; if(result->IsNativeError()) { return ThrowException(result); } return scope.Close(result); }
/*static*/ v8::Handle<v8::Value> JavaObject::methodCall(const v8::Arguments& args) { v8::HandleScope scope; JavaObject* self = node::ObjectWrap::Unwrap<JavaObject>(args.This()); JNIEnv *env = self->m_java->getJavaEnv(); JavaScope javaScope(env); v8::String::AsciiValue methodName(args.Data()); std::string methodNameStr = *methodName; int argsStart = 0; int argsEnd = args.Length(); // arguments ARGS_BACK_CALLBACK(); if(!callbackProvided && methodNameStr == "toString") { return methodCallSync(args); } jobjectArray methodArgs = v8ToJava(env, args, argsStart, argsEnd); jobject method = javaFindMethod(env, self->m_class, methodNameStr, methodArgs); if(method == NULL) { std::string msg = methodNotFoundToString(env, self->m_class, methodNameStr, false, args, argsStart, argsEnd); EXCEPTION_CALL_CALLBACK(msg); return v8::Undefined(); } // run InstanceMethodCallBaton* baton = new InstanceMethodCallBaton(self->m_java, self, method, methodArgs, callback); baton->run(); END_CALLBACK_FUNCTION("\"Method '" << methodNameStr << "' called without a callback did you mean to use the Sync version?\""); }
jobject v8ToJava(JNIEnv* env, v8::Local<v8::Value> arg) { if(arg->IsNull() || arg->IsUndefined()) { return NULL; } if(arg->IsArray()) { v8::Local<v8::Array> array = v8::Array::Cast(*arg); uint32_t arraySize = array->Length(); jclass objectClazz = env->FindClass("java/lang/Object"); jobjectArray result = env->NewObjectArray(arraySize, objectClazz, NULL); for(uint32_t i=0; i<arraySize; i++) { jobject val = v8ToJava(env, array->Get(i)); env->SetObjectArrayElement(result, i, val); } return result; } if(arg->IsString()) { v8::String::AsciiValue val(arg->ToString()); return env->NewStringUTF(*val); } if(arg->IsInt32() || arg->IsUint32()) { jint val = arg->ToInt32()->Value(); jclass clazz = env->FindClass("java/lang/Integer"); jmethodID constructor = env->GetMethodID(clazz, "<init>", "(I)V"); return env->NewObject(clazz, constructor, val); } if(arg->IsNumber()) { jdouble val = arg->ToNumber()->Value(); jclass clazz = env->FindClass("java/lang/Double"); jmethodID constructor = env->GetMethodID(clazz, "<init>", "(D)V"); return env->NewObject(clazz, constructor, val); } if(arg->IsBoolean()) { jboolean val = arg->ToBoolean()->Value(); jclass clazz = env->FindClass("java/lang/Boolean"); jmethodID constructor = env->GetMethodID(clazz, "<init>", "(Z)V"); return env->NewObject(clazz, constructor, val); } if(arg->IsObject()) { v8::Local<v8::Object> obj = v8::Object::Cast(*arg); v8::String::AsciiValue constructorName(obj->GetConstructorName()); if(strcmp(*constructorName, "JavaObject") == 0) { JavaObject* javaObject = node::ObjectWrap::Unwrap<JavaObject>(obj); return javaObject->getObject(); } } // TODO: handle other arg types v8::String::AsciiValue typeStr(arg); printf("Unhandled type: %s\n", *typeStr); return NULL; }
std::string methodNotFoundToString(JNIEnv *env, jclass clazz, std::string methodName, bool constructor, const v8::Arguments& args, int argStart, int argEnd) { std::ostringstream startOfMessage; std::ostringstream msg; jclass classClazz = env->FindClass("java/lang/Class"); jmethodID class_getName = env->GetMethodID(classClazz, "getName", "()Ljava/lang/String;"); startOfMessage << "Could not find method \"" << methodName.c_str() << "("; for(int i=argStart; i<argEnd; i++) { jobject val = v8ToJava(env, args[i]); if(i != argStart) { startOfMessage << ", "; } if(val == NULL) { startOfMessage << "(null)"; } else { jclass argClass = env->GetObjectClass(val); jstring argClassNameJava = (jstring)env->CallObjectMethod(argClass, class_getName); std::string argClassName = javaToString(env, argClassNameJava); startOfMessage << argClassName; } } startOfMessage << ")\" on class \""<< javaObjectToString(env, clazz).c_str() << "\"."; msg << startOfMessage.str() << " Possible matches:\n"; jclass memberClazz = env->FindClass("java/lang/reflect/Member"); jmethodID member_getName = env->GetMethodID(memberClazz, "getName", "()Ljava/lang/String;"); std::list<jobject> methods; if(constructor) { javaReflectionGetConstructors(env, clazz, &methods); } else { javaReflectionGetMethods(env, clazz, &methods, true); } int count = 0; for(std::list<jobject>::iterator it = methods.begin(); it != methods.end(); ++it) { jstring methodNameTestJava = (jstring)env->CallObjectMethod(*it, member_getName); std::string methodNameTest = javaToString(env, methodNameTestJava); if(methodNameTest == methodName) { msg << " " << javaObjectToString(env, *it).c_str() << "\n"; count++; } } if(count == 0) { std::ostringstream noMethodsMsg; noMethodsMsg << startOfMessage.str() << " No methods with that name."; return noMethodsMsg.str(); } return msg.str(); }
jobjectArray v8ToJava(JNIEnv* env, const v8::Arguments& args, int start, int end) { jclass clazz = env->FindClass("java/lang/Object"); jobjectArray results = env->NewObjectArray(end-start, clazz, NULL); for(int i=start; i<end; i++) { jobject val = v8ToJava(env, args[i]); env->SetObjectArrayElement(results, i - start, val); } return results; }
jobject v8ToJava(JNIEnv* env, v8::Local<v8::Value> arg) { if(arg.IsEmpty() || arg->IsNull() || arg->IsUndefined()) { return NULL; } if(arg->IsArray()) { v8::Local<v8::Array> array = v8::Array::Cast(*arg); uint32_t arraySize = array->Length(); jclass objectClazz = env->FindClass("java/lang/Object"); jobjectArray result = env->NewObjectArray(arraySize, objectClazz, NULL); for(uint32_t i=0; i<arraySize; i++) { jobject val = v8ToJava(env, array->Get(i)); env->SetObjectArrayElement(result, i, val); } return result; } if(arg->IsString()) { v8::String::Utf8Value val(arg->ToString()); return env->NewStringUTF(*val); } if(arg->IsInt32() || arg->IsUint32()) { jint val = arg->ToInt32()->Value(); jclass clazz = env->FindClass("java/lang/Integer"); jmethodID constructor = env->GetMethodID(clazz, "<init>", "(I)V"); return env->NewObject(clazz, constructor, val); } if(arg->IsNumber()) { jdouble val = arg->ToNumber()->Value(); jclass clazz = env->FindClass("java/lang/Double"); jmethodID constructor = env->GetMethodID(clazz, "<init>", "(D)V"); return env->NewObject(clazz, constructor, val); } if(arg->IsBoolean()) { jboolean val = arg->ToBoolean()->Value(); jclass clazz = env->FindClass("java/lang/Boolean"); jmethodID constructor = env->GetMethodID(clazz, "<init>", "(Z)V"); return env->NewObject(clazz, constructor, val); } if(arg->IsObject()) { v8::Local<v8::Object> obj = v8::Object::Cast(*arg); v8::Local<v8::Value> isJavaObject = obj->GetHiddenValue(v8::String::New(V8_HIDDEN_MARKER_JAVA_OBJECT)); if(!isJavaObject.IsEmpty() && isJavaObject->IsBoolean()) { return v8ToJava_javaObject(env, obj); } v8::Local<v8::Value> isJavaLong = obj->GetHiddenValue(v8::String::New(V8_HIDDEN_MARKER_JAVA_LONG)); if(!isJavaLong.IsEmpty() && isJavaLong->IsBoolean()) { return v8ToJava_javaLong(env, obj); } } // TODO: handle other arg types v8::String::AsciiValue typeStr(arg); printf("v8ToJava: Unhandled type: %s\n", *typeStr); return NULL; }
void EIO_AfterCallJs(uv_work_t* req, int status) { #else void EIO_AfterCallJs(uv_work_t* req) { #endif DynamicProxyData* dynamicProxyData = static_cast<DynamicProxyData*>(req->data); if(!dynamicProxyDataVerify(dynamicProxyData)) { return; } dynamicProxyData->result = NULL; JNIEnv* env; int ret = dynamicProxyData->java->getJvm()->GetEnv((void**)&env, JNI_BEST_VERSION); if (ret != JNI_OK) { dynamicProxyData->throwableClass = "java/lang/IllegalStateException"; dynamicProxyData->throwableMessage = "Could not retrieve JNIEnv: jvm->GetEnv returned " + to_string<int>(ret); dynamicProxyData->done = DYNAMIC_PROXY_JS_ERROR; return; } Nan::HandleScope scope; v8::Array* v8Args; v8::Function* fn; v8::Handle<v8::Value>* argv; int argc; int i; v8::Local<v8::Value> v8Result; jobject javaResult; v8::Local<v8::Object> dynamicProxyDataFunctions = Nan::New(dynamicProxyData->functions); v8::Local<v8::Value> fnObj = dynamicProxyDataFunctions->Get(Nan::New<v8::String>(dynamicProxyData->methodName.c_str()).ToLocalChecked()); if(fnObj->IsUndefined() || fnObj->IsNull()) { dynamicProxyData->throwableClass = "java/lang/NoSuchMethodError"; dynamicProxyData->throwableMessage = "Could not find js function " + dynamicProxyData->methodName; dynamicProxyData->done = DYNAMIC_PROXY_JS_ERROR; return; } if(!fnObj->IsFunction()) { dynamicProxyData->throwableClass = "java/lang/IllegalStateException"; dynamicProxyData->throwableMessage = dynamicProxyData->methodName + " is not a function"; dynamicProxyData->done = DYNAMIC_PROXY_JS_ERROR; return; } fn = v8::Function::Cast(*fnObj); if(dynamicProxyData->args) { v8Args = v8::Array::Cast(*javaArrayToV8(dynamicProxyData->java, env, dynamicProxyData->args)); argc = v8Args->Length(); } else { argc = 0; } argv = new v8::Handle<v8::Value>[argc]; for(i=0; i<argc; i++) { argv[i] = v8Args->Get(i); } Nan::TryCatch tryCatch; tryCatch.SetCaptureMessage(true); v8Result = fn->Call(dynamicProxyDataFunctions, argc, argv); delete[] argv; if (tryCatch.HasCaught()) { dynamicProxyData->throwableClass = "node/NodeJsException"; v8::String::Utf8Value message(tryCatch.Message()->Get()); dynamicProxyData->throwableMessage = std::string(*message); tryCatch.Reset(); dynamicProxyData->done = DYNAMIC_PROXY_JS_ERROR; return; } if(!dynamicProxyDataVerify(dynamicProxyData)) { return; } javaResult = v8ToJava(env, v8Result); if(javaResult == NULL) { dynamicProxyData->result = NULL; } else { dynamicProxyData->result = env->NewGlobalRef(javaResult); } dynamicProxyData->done = true; }