Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/jni/ArrayElementAccessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,13 +191,13 @@ void ArrayElementAccessor::SetArrayElement(const Handle<Object>& array, uint32_t
else
{
JsArgToArrayConverter::Error err = argConverter.GetError();
ExceptionUtil::GetInstance()->HandleInvalidState(err.msg, false);
ExceptionUtil::GetInstance()->ThrowExceptionToJs(err.msg);
return;
}
}
else
{
ExceptionUtil::GetInstance()->HandleInvalidState("Cannot assign primitive value to array of objects.", false);
ExceptionUtil::GetInstance()->ThrowExceptionToJs("Cannot assign primitive value to array of objects.");
return;
}
}
Expand All @@ -217,7 +217,7 @@ Handle<Value> ArrayElementAccessor::CheckForArrayAccessException(JEnv& env, cons
env.ExceptionClear();
string errMsg;
ExceptionUtil::GetInstance()->GetExceptionMessage(env, exc, errMsg);
ExceptionUtil::GetInstance()->HandleInvalidState(errMsg, false);
ExceptionUtil::GetInstance()->ThrowExceptionToJs(errMsg);
}
else if (elementSignature == "Z")
{
Expand Down
57 changes: 25 additions & 32 deletions src/jni/ExceptionUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,36 +115,19 @@ void ExceptionUtil::GetExceptionMessage(JEnv& env, jthrowable exception, string&
}
}

void ExceptionUtil::HandleInvalidState(const string& message, bool fail){
if(fail){
NativeScriptRuntime::APP_FAIL(message.c_str());
}
else {
auto error = Exception::Error(ConvertToV8String(message));
Isolate::GetCurrent()->ThrowException(error);
}
}

bool ExceptionUtil::HandleTryCatch(TryCatch& tc, bool rethrow){
bool ExceptionUtil::HandleTryCatch(TryCatch& tc, const string& prependMessage){
if(!tc.HasCaught()){
return false;
}

if(rethrow)
{
if(tc.CanContinue()){
auto message = tc.Message();
auto error = tc.Exception();
OnUncaughtError(message, error); //calls JS global function("__onUncaughtError") passing the uncaught error
}
else {
auto errorMessage = PrintErrorMessage(tc.Message(), tc.Exception());

stringstream ss;
ss << "An uncaught error has occurred and V8's TryCatch block may not be continued. Error is: " << errorMessage;
if(tc.CanContinue()){
ThrowExceptionToJava(tc, prependMessage);
}
else {
stringstream ss;
ss << endl << "An uncaught error has occurred and V8's TryCatch block may not be continued. Error is: ";

HandleInvalidState(ss.str(), true);
}
ExceptionUtil::GetInstance()->ThrowExceptionToJava(tc, ss.str());
}

return true;
Expand Down Expand Up @@ -206,12 +189,12 @@ string ExceptionUtil::GetErrorMessage(const Handle<Message>& message, const Hand
str = String::NewFromUtf8(Isolate::GetCurrent(), "");
}
String::Utf8Value utfError(str);
ss << *utfError << endl;
ss << endl << endl << *utfError << endl;
ss << "File: \"" << ConvertToString(message->GetScriptResourceName().As<String>());
ss << ", line: " << message->GetLineNumber() - Constants::MODULE_LINES_OFFSET << ", column: " << message->GetStartColumn() << endl;
ss << ", line: " << message->GetLineNumber() - Constants::MODULE_LINES_OFFSET << ", column: " << message->GetStartColumn() << endl << endl;

string stackTraceMessage = GetErrorStackTrace(message->GetStackTrace());
ss << "StackTrace: " << endl << stackTraceMessage;
ss << "StackTrace: " << endl << stackTraceMessage << endl;

return ss.str();
}
Expand Down Expand Up @@ -258,18 +241,21 @@ string ExceptionUtil::GetErrorStackTrace(const Handle<StackTrace>& stackTrace)
return ss.str();
}

bool ExceptionUtil::ThrowExceptionToJava(TryCatch& tc)
bool ExceptionUtil::ThrowExceptionToJava(TryCatch& tc, const string& prependMessage)
{
Isolate *isolate = Isolate::GetCurrent();
auto ex = tc.Exception();
string loggedMessage = PrintErrorMessage(tc.Message(), ex);
string message = PrintErrorMessage(tc.Message(), ex);
stringstream ss;
ss << endl << prependMessage << message;
string loggedMessage = ss.str();

DEBUG_WRITE("Error: %s", loggedMessage.c_str());

JEnv env;
env.ExceptionClear();
if (tc.CanContinue())
{
JEnv env;

jweak javaThrowable = nullptr;
if (ex->IsObject())
{
Expand Down Expand Up @@ -303,6 +289,13 @@ bool ExceptionUtil::ThrowExceptionToJava(TryCatch& tc)
}
}

void ExceptionUtil::ThrowExceptionToJs(const string& exceptionMessage)
{
Isolate *isolate(Isolate::GetCurrent());
Local<Value> exception = v8::Exception::Error(ConvertToV8String(exceptionMessage));
isolate->ThrowException(exception);
}

bool ExceptionUtil::CheckForJavaException(JEnv& env)
{
bool exceptionOccurred = env.ExceptionCheck() == JNI_TRUE;
Expand Down
8 changes: 5 additions & 3 deletions src/jni/ExceptionUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ namespace tns

bool CheckForJavaException(JEnv& env);

bool ThrowExceptionToJava(v8::TryCatch& tc);
bool ThrowExceptionToJava(v8::TryCatch& tc, const std::string& prependMessage = "");

void ThrowExceptionToJs(const std::string& exceptionMessage);

void GetExceptionMessage(JEnv& env, jthrowable exception, std::string& errMsg);

Expand All @@ -26,15 +28,15 @@ namespace tns
* - The flow may continue. In this case a check for nested TryCatch blocks will be made and if such exist the error will be re-thrown.
* - The flow may not continue. In this case a call the NativeScriptRuntime::APP_FAIL will be made. This will go to Java where the Java VM will be shut down.
*/
bool HandleTryCatch(v8::TryCatch& tc, bool rethrow);
bool HandleTryCatch(v8::TryCatch& tc, const std::string& prependMessage = "");

/**
* Provides an entry point to handle states considered invalid for the NativeScript runtime.
* There are two invalid states:
* - A state which does not break the whole runtime. In this case a JavaScript error will be raised.
* - A state which breaks the runtime flow. In this case a call the NativeScriptRuntime::APP_FAIL will be made. This will go to Java where the Java VM will be shut down.
*/
void HandleInvalidState(const std::string& message, bool fail);
void HandleInvalidState(const std::string& message);

/**
* A callback to the V8's AddMessageListener method.
Expand Down
22 changes: 8 additions & 14 deletions src/jni/MetadataNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ void MetadataNode::FieldAccessorSetterCallback(Local<String> property,Local<Valu
ss << "You are trying to set \"" << fieldCallbackData.name << "\" which is a final field! Final fields can only be read.";
string exceptionMessage = ss.str();

info.GetIsolate()->ThrowException(v8::Exception::Error((ConvertToV8String(exceptionMessage))));
ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage);
}
else
{
Expand Down Expand Up @@ -983,8 +983,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo<Value>& in
ss << "Invalid extend() call. No name specified for extend at location: " << extendLocation.c_str();
string exceptionMessage = ss.str();

Isolate *isolate(Isolate::GetCurrent());
isolate->ThrowException(v8::Exception::Error((ConvertToV8String(exceptionMessage))));
ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage);
return false;
}

Expand All @@ -995,8 +994,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo<Value>& in
ss << "Invalid extend() call. No implementation object specified at location: " << extendLocation.c_str();
string exceptionMessage = ss.str();

Isolate *isolate(Isolate::GetCurrent());
isolate->ThrowException(v8::Exception::Error((ConvertToV8String(exceptionMessage))));
ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage);
return false;
}

Expand All @@ -1010,8 +1008,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo<Value>& in
ss << "Invalid extend() call. No name for extend specified at location: " << extendLocation.c_str();
string exceptionMessage = ss.str();

Isolate *isolate(Isolate::GetCurrent());
isolate->ThrowException(v8::Exception::Error((ConvertToV8String(exceptionMessage))));
ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage);
return false;
}

Expand All @@ -1021,8 +1018,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo<Value>& in
ss << "Invalid extend() call. Named extend should be called with second object parameter containing overridden methods at location: " << extendLocation.c_str();
string exceptionMessage = ss.str();

Isolate *isolate(Isolate::GetCurrent());
isolate->ThrowException(v8::Exception::Error((ConvertToV8String(exceptionMessage))));
ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage);
return false;
}

Expand All @@ -1035,8 +1031,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo<Value>& in
ss << "The extend name \"" << ConvertToString(extendName) << "\" you provided contains invalid symbols. Try using the symbols [a-z, A-Z, 0-9, _]." << endl;
string exceptionMessage = ss.str();

Isolate *isolate(Isolate::GetCurrent());
isolate->ThrowException(v8::Exception::Error((ConvertToV8String(exceptionMessage))));
ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage);
return false;
}
implementationObject = info[1]->ToObject();
Expand All @@ -1047,8 +1042,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo<Value>& in
ss << "Invalid extend() call at location: " << extendLocation.c_str();
string exceptionMessage = ss.str();

Isolate *isolate(Isolate::GetCurrent());
isolate->ThrowException(v8::Exception::Error((ConvertToV8String(exceptionMessage))));
ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage);
return false;
}

Expand Down Expand Up @@ -1111,7 +1105,7 @@ void MetadataNode::ExtendCallMethodHandler(const v8::FunctionCallbackInfo<v8::Va
string usedClassName = ConvertToString(implementationObjectProperty);
stringstream s;
s << "This object is used to extend another class '" << usedClassName << "'";
ExceptionUtil::GetInstance()->HandleInvalidState(s.str(), false);
ExceptionUtil::GetInstance()->ThrowExceptionToJs(s.str());
return;
}

Expand Down
25 changes: 9 additions & 16 deletions src/jni/NativeScriptRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ void NativeScriptRuntime::CallJavaMethod(const Handle<Object>& caller, const str
if (!argConverter.IsValid())
{
JsArgConverter::Error err = argConverter.GetError();
ExceptionUtil::GetInstance()->HandleInvalidState(err.msg, false);
ExceptionUtil::GetInstance()->ThrowExceptionToJs(err.msg);
return;
}

Expand Down Expand Up @@ -624,7 +624,7 @@ jobject NativeScriptRuntime::CreateJavaInstance(int objectID, const std::string&
else
{
JsArgToArrayConverter::Error err = argConverter.GetError();
ExceptionUtil::GetInstance()->HandleInvalidState(err.msg, false);
ExceptionUtil::GetInstance()->ThrowExceptionToJs(err.msg);
}

return instance;
Expand Down Expand Up @@ -819,7 +819,7 @@ void NativeScriptRuntime::RequireCallback(const v8::FunctionCallbackInfo<v8::Val
stringstream ss;
ss << "Module \"" << moduleName << "\" not found";
string exception = ss.str();
ExceptionUtil::GetInstance()->HandleInvalidState(exception, false);
ExceptionUtil::GetInstance()->ThrowExceptionToJs(exception);
return;
}
if (modulePath == "EXTERNAL_FILE_ERROR")
Expand All @@ -828,7 +828,7 @@ void NativeScriptRuntime::RequireCallback(const v8::FunctionCallbackInfo<v8::Val
stringstream ss;
ss << "Module \"" << moduleName << "\" is located on the external storage. Modules can be private application files ONLY";
string exception = ss.str();
ExceptionUtil::GetInstance()->HandleInvalidState(exception, false);
ExceptionUtil::GetInstance()->ThrowExceptionToJs(exception);
return;
}

Expand All @@ -851,7 +851,7 @@ void NativeScriptRuntime::RequireCallback(const v8::FunctionCallbackInfo<v8::Val
auto script = Script::Compile(scriptText, args[0].As<String>());
DEBUG_WRITE("Compiled script (module %s)", moduleName.c_str());

if(ExceptionUtil::GetInstance()->HandleTryCatch(tc, true)){
if(ExceptionUtil::GetInstance()->HandleTryCatch(tc)){
loadedModules.erase(modulePath);
tmpExportObj->Reset();
delete tmpExportObj;
Expand All @@ -869,12 +869,11 @@ void NativeScriptRuntime::RequireCallback(const v8::FunctionCallbackInfo<v8::Val

DEBUG_WRITE("After Running script (module %s)", moduleName.c_str());

if(ExceptionUtil::GetInstance()->HandleTryCatch(tcRequire, true)){
if(ExceptionUtil::GetInstance()->HandleTryCatch(tcRequire)){
loadedModules.erase(modulePath);
tmpExportObj->Reset();
delete tmpExportObj;
hasError = true;
tcRequire.ReThrow();
}
else {
if (moduleObj.IsEmpty())
Expand All @@ -897,11 +896,6 @@ void NativeScriptRuntime::RequireCallback(const v8::FunctionCallbackInfo<v8::Val
}
}
}

if (tc.HasCaught())
{
tc.ReThrow();
}
}
else
{
Expand Down Expand Up @@ -1027,7 +1021,7 @@ Handle<Value> NativeScriptRuntime::CallJSMethod(JNIEnv *_env, const Handle<Objec
stringstream ss;
ss << "Cannot find method '" << name << "' implementation";

ExceptionUtil::GetInstance()->HandleInvalidState(ss.str(), false);
ExceptionUtil::GetInstance()->ThrowExceptionToJs(ss.str());

result = Undefined(isolate);
}
Expand All @@ -1038,7 +1032,7 @@ Handle<Value> NativeScriptRuntime::CallJSMethod(JNIEnv *_env, const Handle<Objec
stringstream ss;
ss << "Property '" << name << "' is not a function";

ExceptionUtil::GetInstance()->HandleInvalidState(ss.str(), false);
ExceptionUtil::GetInstance()->ThrowExceptionToJs(ss.str());

result = Undefined(isolate);
}
Expand All @@ -1062,8 +1056,7 @@ Handle<Value> NativeScriptRuntime::CallJSMethod(JNIEnv *_env, const Handle<Objec

//TODO: if javaResult is a pure js object create a java object that represents this object in java land

bool exceptionFound = exceptionUtil->HandleTryCatch(tc, true);
if (exceptionFound)
if (tc.HasCaught())
{
jsResult = Undefined(isolate);
}
Expand Down
6 changes: 3 additions & 3 deletions src/jni/WeakRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,17 @@ void WeakRef::ConstructorCallback(const FunctionCallbackInfo<Value>& args)
}
else
{
ExceptionUtil::GetInstance()->HandleInvalidState("The WeakRef constructor expects an object argument.", false);
ExceptionUtil::GetInstance()->ThrowExceptionToJs("The WeakRef constructor expects an object argument.");
}
}
else
{
ExceptionUtil::GetInstance()->HandleInvalidState("The WeakRef constructor expects single parameter.", false);
ExceptionUtil::GetInstance()->ThrowExceptionToJs("The WeakRef constructor expects single parameter.");
}
}
else
{
ExceptionUtil::GetInstance()->HandleInvalidState("WeakRef must be used as a construct call.", false);
ExceptionUtil::GetInstance()->ThrowExceptionToJs("WeakRef must be used as a construct call.");
}
}

Expand Down
Loading