Skip to content

Commit 8c635a5

Browse files
committed
Merge pull request #409 from NativeScript/pete/nullobjoverload
Fix issue #90
2 parents 1116046 + 3fc4243 commit 8c635a5

17 files changed

Lines changed: 383 additions & 25 deletions

src/jni/JsArgConverter.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,14 @@ bool JsArgConverter::ConvertArg(const Local<Value>& arg, int index)
204204

205205
case CastType::None:
206206
obj = objectManager->GetJavaObjectByJsObject(jsObject);
207+
208+
castValue = jsObject->GetHiddenValue(ConvertToV8String(V8StringConstants::NULL_NODE_NAME));
209+
if(!castValue.IsEmpty()) {
210+
SetConvertedObject(index, nullptr);
211+
success = true;
212+
return success;
213+
}
214+
207215
success = !obj.IsNull();
208216

209217
if (success)

src/jni/JsArgToArrayConverter.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "NumericCasts.h"
1414
#include "NativeScriptException.h"
1515
#include "Runtime.h"
16+
#include "MetadataNode.h"
1617

1718
using namespace v8;
1819
using namespace std;
@@ -287,6 +288,40 @@ bool JsArgToArrayConverter::ConvertArg(const Local<Value>& arg, int index)
287288

288289
case CastType::None:
289290
obj = objectManager->GetJavaObjectByJsObject(jsObj);
291+
292+
castValue = jsObj->GetHiddenValue(V8StringConstants::GetNullNodeName());
293+
294+
if(!castValue.IsEmpty()) {
295+
auto node = reinterpret_cast<MetadataNode*>(castValue.As<External>()->Value());
296+
297+
if(node == nullptr) {
298+
s << "Cannot get type of the null argument at index " << index;
299+
success = false;
300+
break;
301+
}
302+
303+
auto type = node->GetName();
304+
auto nullObjName = "com/tns/NullObject";
305+
auto nullObjCtorSig = "(Ljava/lang/Class;)V";
306+
307+
jclass nullClazz = env.FindClass(nullObjName);
308+
jmethodID ctor = env.GetMethodID(nullClazz, "<init>", nullObjCtorSig);
309+
jclass clazzToNull = env.FindClass(type.c_str());
310+
jobject nullObjType = env.NewObject(nullClazz, ctor, clazzToNull);
311+
312+
if(nullObjType != nullptr)
313+
{
314+
SetConvertedObject(env, index, nullObjType, false);
315+
}
316+
else
317+
{
318+
SetConvertedObject(env, index, nullptr);
319+
}
320+
321+
success = true;
322+
return success;
323+
}
324+
290325
success = !obj.IsNull();
291326
if (success)
292327
{
@@ -300,7 +335,6 @@ bool JsArgToArrayConverter::ConvertArg(const Local<Value>& arg, int index)
300335

301336
default:
302337
throw NativeScriptException("Unsupported cast type");
303-
304338
}
305339
}
306340
else if (arg->IsUndefined() || arg->IsNull())

src/jni/MetadataNode.cpp

Lines changed: 83 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ void MetadataNode::Init()
2525
}
2626

2727
MetadataNode::MetadataNode(MetadataTreeNode *treeNode) :
28-
m_treeNode(treeNode)
28+
m_treeNode(treeNode)
2929
{
3030
uint8_t nodeType = s_metadataReader.GetNodeType(treeNode);
3131

@@ -42,9 +42,9 @@ MetadataNode::MetadataNode(MetadataTreeNode *treeNode) :
4242
bool isPrefix;
4343
auto impTypeName = s_metadataReader.ReadInterfaceImplementationTypeName(m_treeNode, isPrefix);
4444
m_implType = isPrefix
45-
? (impTypeName + m_name)
46-
:
47-
impTypeName;
45+
? (impTypeName + m_name)
46+
:
47+
impTypeName;
4848
}
4949
}
5050

@@ -274,6 +274,63 @@ void MetadataNode::ClassAccessorGetterCallback(Local<String> property, const Pro
274274
}
275275
}
276276

277+
void MetadataNode::NullObjectAccessorGetterCallback(Local<String> property,const PropertyCallbackInfo<Value>& info)
278+
{
279+
try
280+
{
281+
DEBUG_WRITE("NullObjectAccessorGetterCallback");
282+
auto isolate = info.GetIsolate();
283+
284+
auto thiz = info.This();
285+
if((thiz->GetHiddenValue(V8StringConstants::GetNullNodeName())).IsEmpty())
286+
{
287+
auto node = reinterpret_cast<MetadataNode*>(info.Data().As<External>()->Value());
288+
thiz->SetHiddenValue(V8StringConstants::GetNullNodeName(), External::New(isolate, node));
289+
auto funcTemplate = FunctionTemplate::New(isolate, MetadataNode::NullValueOfCallback);
290+
thiz->Delete(V8StringConstants::GetValueOf());
291+
thiz->Set(V8StringConstants::GetValueOf(), funcTemplate->GetFunction());
292+
}
293+
294+
info.GetReturnValue().Set(thiz);
295+
}
296+
catch (NativeScriptException& e)
297+
{
298+
e.ReThrowToV8();
299+
}
300+
catch (std::exception e) {
301+
stringstream ss;
302+
ss << "Error: c++ exception: " << e.what() << endl;
303+
NativeScriptException nsEx(ss.str());
304+
nsEx.ReThrowToV8();
305+
}
306+
catch (...) {
307+
NativeScriptException nsEx(std::string("Error: c++ exception!"));
308+
nsEx.ReThrowToV8();
309+
}
310+
}
311+
312+
void MetadataNode::NullValueOfCallback(const FunctionCallbackInfo<Value>& args) {
313+
try
314+
{
315+
auto isolate = args.GetIsolate();
316+
args.GetReturnValue().Set(Null(isolate));
317+
}
318+
catch (NativeScriptException& e)
319+
{
320+
e.ReThrowToV8();
321+
}
322+
catch (std::exception e) {
323+
stringstream ss;
324+
ss << "Error: c++ exception: " << e.what() << endl;
325+
NativeScriptException nsEx(ss.str());
326+
nsEx.ReThrowToV8();
327+
}
328+
catch (...) {
329+
NativeScriptException nsEx(std::string("Error: c++ exception!"));
330+
nsEx.ReThrowToV8();
331+
}
332+
}
333+
277334
void MetadataNode::FieldAccessorGetterCallback(Local<String> property, const PropertyCallbackInfo<Value>& info)
278335
{
279336
try
@@ -356,28 +413,26 @@ void MetadataNode::SuperAccessorGetterCallback(Local<String> property, const Pro
356413
{
357414
auto thiz = info.This();
358415
auto isolate = info.GetIsolate();
359-
auto k = ConvertToV8String("supervalue");
360-
auto superValue = thiz->GetHiddenValue(k).As<Object>();
416+
auto key = ConvertToV8String("supervalue");
417+
auto superValue = thiz->GetHiddenValue(key).As<Object>();
361418
if (superValue.IsEmpty())
362419
{
363420
auto runtime = Runtime::GetRuntime(isolate);
364421
auto objectManager = runtime->GetObjectManager();
365422

366423
superValue = objectManager->GetEmptyObject(isolate);
367-
bool d = superValue->Delete(ConvertToV8String("toString"));
368-
d = superValue->Delete(ConvertToV8String("valueOf"));
424+
bool d = superValue->Delete(V8StringConstants::GetToString());
425+
d = superValue->Delete(V8StringConstants::GetValueOf());
369426
superValue->SetInternalField(static_cast<int>(ObjectManager::MetadataNodeKeys::CallSuper), True(isolate));
370427

371428
superValue->SetPrototype(thiz->GetPrototype().As<Object>()->GetPrototype().As<Object>()->GetPrototype());
372-
thiz->SetHiddenValue(k, superValue);
429+
thiz->SetHiddenValue(key, superValue);
373430
objectManager->CloneLink(thiz, superValue);
374431

375432
DEBUG_WRITE("superValue.GetPrototype=%d", superValue->GetPrototype().As<Object>()->GetIdentityHash());
376433

377434
auto node = GetInstanceMetadata(isolate, thiz);
378435
SetInstanceMetadata(isolate, superValue, node);
379-
380-
thiz->SetHiddenValue(k, superValue);
381436
}
382437

383438
info.GetReturnValue().Set(superValue);
@@ -404,8 +459,8 @@ Local<Function> MetadataNode::SetMembers(Isolate *isolate, Local<FunctionTemplat
404459

405460
return hasCustomMetadata
406461
? SetMembersFromRuntimeMetadata(isolate, ctorFuncTemplate, prototypeTemplate, instanceMethodsCallbackData, baseInstanceMethodsCallbackData, treeNode)
407-
:
408-
SetMembersFromStaticMetadata(isolate, ctorFuncTemplate, prototypeTemplate, instanceMethodsCallbackData, baseInstanceMethodsCallbackData, treeNode);
462+
:
463+
SetMembersFromStaticMetadata(isolate, ctorFuncTemplate, prototypeTemplate, instanceMethodsCallbackData, baseInstanceMethodsCallbackData, treeNode);
409464
}
410465

411466
Local<Function> MetadataNode::SetMembersFromStaticMetadata(Isolate *isolate, Local<FunctionTemplate>& ctorFuncTemplate, Local<ObjectTemplate>& prototypeTemplate, vector<MethodCallbackData*>& instanceMethodsCallbackData, const vector<MethodCallbackData*>& baseInstanceMethodsCallbackData, MetadataTreeNode *treeNode)
@@ -443,7 +498,7 @@ Local<Function> MetadataNode::SetMembersFromStaticMetadata(Isolate *isolate, Loc
443498
auto itBegin = baseInstanceMethodsCallbackData.begin();
444499
auto itEnd = baseInstanceMethodsCallbackData.end();
445500
auto itFound = find_if(itBegin, itEnd, [&entry] (MethodCallbackData *x)
446-
{ return x->candidates.front().name == entry.name;});
501+
{ return x->candidates.front().name == entry.name;});
447502
if (itFound != itEnd)
448503
{
449504
callbackData->parent = *itFound;
@@ -510,6 +565,11 @@ Local<Function> MetadataNode::SetMembersFromStaticMetadata(Isolate *isolate, Loc
510565
ctorFunction->SetAccessor(fieldName, FieldAccessorGetterCallback, FieldAccessorSetterCallback, fieldData, AccessControl::DEFAULT, PropertyAttribute::DontDelete);
511566
}
512567

568+
auto nullObjectName = V8StringConstants::GetNullObject();
569+
570+
Local<Value> nullObjectData = External::New(isolate, this);
571+
ctorFunction->SetAccessor(nullObjectName, NullObjectAccessorGetterCallback, nullptr, nullObjectData);
572+
513573
SetClassAccessor(ctorFunction);
514574

515575
return ctorFunction;
@@ -563,7 +623,7 @@ Local<Function> MetadataNode::SetMembersFromRuntimeMetadata(Isolate *isolate, Lo
563623
auto itBegin = baseInstanceMethodsCallbackData.begin();
564624
auto itEnd = baseInstanceMethodsCallbackData.end();
565625
auto itFound = find_if(itBegin, itEnd, [&entry] (MethodCallbackData *x)
566-
{ return x->candidates.front().name == entry.name;});
626+
{ return x->candidates.front().name == entry.name;});
567627
if (itFound != itEnd)
568628
{
569629
callbackData->parent = *itFound;
@@ -876,7 +936,7 @@ void MetadataNode::InterfaceConstructorCallback(const v8::FunctionCallbackInfo<v
876936
{
877937
if (!extendLocationFound)
878938
{
879-
stringstream ss;
939+
stringstream ss;
880940
ss << "(InternalError): Invalid extend() call. No name specified for extend. Location: " << extendLocation.c_str();
881941
throw NativeScriptException(ss.str());
882942
}
@@ -988,6 +1048,7 @@ void MetadataNode::MethodCallback(const v8::FunctionCallbackInfo<v8::Value>& inf
9881048

9891049
auto callbackData = reinterpret_cast<MethodCallbackData*>(e->Value());
9901050

1051+
// Number of arguments the method is invoked with
9911052
int argLength = info.Length();
9921053

9931054
MetadataEntry *entry = nullptr;
@@ -1002,17 +1063,20 @@ void MetadataNode::MethodCallback(const v8::FunctionCallbackInfo<v8::Value>& inf
10021063

10031064
className = &callbackData->node->m_name;
10041065

1066+
// Iterates through all methods and finds the best match based on the number of arguments
10051067
auto found = false;
10061068
for (auto& c : candidates)
10071069
{
10081070
found = c.paramCount == argLength;
10091071
if (found)
10101072
{
10111073
entry = &c;
1074+
DEBUG_WRITE("MetaDataEntry Method %s's signature is: %s", entry->name.c_str(), entry->sig.c_str());
10121075
break;
10131076
}
10141077
}
10151078

1079+
// Iterates through the parent class's methods to find a good match
10161080
if (!found)
10171081
{
10181082
callbackData = callbackData->parent;
@@ -1578,9 +1642,9 @@ MetadataEntry MetadataNode::GetChildMetadataForPackage(MetadataNode *node, const
15781642
bool isPrefix;
15791643
string declaringType = s_metadataReader.ReadInterfaceImplementationTypeName(treeNodeChild, isPrefix);
15801644
child.declaringType = isPrefix
1581-
? (declaringType + s_metadataReader.ReadTypeName(child.treeNode))
1582-
:
1583-
declaringType;
1645+
? (declaringType + s_metadataReader.ReadTypeName(child.treeNode))
1646+
:
1647+
declaringType;
15841648
}
15851649
}
15861650
}

src/jni/MetadataNode.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@ namespace tns
210210
static void InnerClassConstructorCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
211211
static void InnerClassAccessorGetterCallback(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info);
212212

213+
static void NullObjectAccessorGetterCallback(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info);
214+
static void NullValueOfCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
215+
213216
static void FieldAccessorGetterCallback(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info);
214217
static void FieldAccessorSetterCallback(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<void>& info);
215218
static void ClassAccessorGetterCallback(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info);

src/jni/MethodCache.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ MethodCache::CacheMethodInfo MethodCache::ResolveMethodSignature(const string& c
6767

6868
return mi;
6969
}
70-
70+
// Encoded signature <className>.S/I.<methodName>.<argsCount>.<arg1class>.<...>
7171
string MethodCache::EncodeSignature(const string& className, const string& methodName, const FunctionCallbackInfo<Value>& args, bool isStatic)
7272
{
7373
string sig(className);
@@ -100,6 +100,22 @@ string MethodCache::GetType(const v8::Local<v8::Value>& value)
100100
{
101101
string type;
102102

103+
if(value->IsObject())
104+
{
105+
auto objVal = value->ToObject();
106+
107+
Local<Value> nullNode = objVal->GetHiddenValue(V8StringConstants::GetNullNodeName());
108+
109+
if(!nullNode.IsEmpty()) {
110+
auto treeNode = reinterpret_cast<MetadataNode*>(nullNode.As<External>()->Value());
111+
112+
type = (treeNode != nullptr) ? treeNode->GetName() : "<unknown>";
113+
114+
DEBUG_WRITE("Parameter of type %s with NULL value is passed to the method.", type.c_str());
115+
return type;
116+
}
117+
}
118+
103119
if (value->IsArray() || value->IsArrayBuffer() || value->IsArrayBufferView() || value->IsTypedArray()
104120
|| value->IsFloat32Array() || value->IsFloat64Array()
105121
|| value->IsInt8Array() || value->IsInt16Array() || value->IsInt32Array()

src/jni/V8StringConstants.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,28 @@ namespace tns
2828
return Local<String>::New(isolate, *EXTEND_PERSISTENT);
2929
}
3030

31+
Local<String> V8StringConstants::GetNullObject()
32+
{
33+
auto isolate = Isolate::GetCurrent();
34+
if (NULL_OBJECT_PERSISTENT == nullptr)
35+
{
36+
auto str = String::NewFromUtf8(isolate, NULL_OBJECT.c_str());
37+
NULL_OBJECT_PERSISTENT = new Persistent<String>(Isolate::GetCurrent(), str);
38+
}
39+
return Local<String>::New(isolate, *NULL_OBJECT_PERSISTENT);
40+
}
41+
42+
Local<String> V8StringConstants::GetNullNodeName()
43+
{
44+
auto isolate = Isolate::GetCurrent();
45+
if (NULL_NODE_NAME_PERSISTENT == nullptr)
46+
{
47+
auto str = String::NewFromUtf8(isolate, NULL_NODE_NAME.c_str());
48+
NULL_NODE_NAME_PERSISTENT = new Persistent<String>(Isolate::GetCurrent(), str);
49+
}
50+
return Local<String>::New(isolate, *NULL_NODE_NAME_PERSISTENT);
51+
}
52+
3153
Local<String> V8StringConstants::GetIsPrototypeImplementationObject()
3254
{
3355
auto isolate = Isolate::GetCurrent();
@@ -184,6 +206,8 @@ namespace tns
184206

185207
const string V8StringConstants::CLASS_IMPLEMENTATION_OBJECT = "t::ClassImplementationObject";
186208
const string V8StringConstants::EXTEND = "extend";
209+
const string V8StringConstants::NULL_OBJECT = "null";
210+
const string V8StringConstants::NULL_NODE_NAME = "nullNode";
187211
const string V8StringConstants::IS_PROTOTYPE_IMPLEMENTATION_OBJECT = "__isPrototypeImplementationObject";
188212
const string V8StringConstants::NATIVE_EXCEPTION = "nativeException";
189213
const string V8StringConstants::STACK_TRACE = "stackTrace";
@@ -209,6 +233,8 @@ namespace tns
209233
// TODO: These are not thread-safe!
210234
Persistent<String> *V8StringConstants::CLASS_IMPLEMENTATION_OBJECT_PERSISTENT;
211235
Persistent<String> *V8StringConstants::EXTEND_PERSISTENT;
236+
Persistent<String> *V8StringConstants::NULL_OBJECT_PERSISTENT;
237+
Persistent<String> *V8StringConstants::NULL_NODE_NAME_PERSISTENT;
212238
Persistent<String> *V8StringConstants::IS_PROTOTYPE_IMPLEMENTATION_OBJECT_PERSISTENT;
213239
Persistent<String> *V8StringConstants::NATIVE_EXCEPTION_PERSISTENT;
214240
Persistent<String> *V8StringConstants::STACK_TRACE_PERSISTENT;

src/jni/V8StringConstants.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ namespace tns
3333
static v8::Local<v8::String> GetClassImplementationObject();
3434
static v8::Local<v8::String> GetDebugName();
3535
static v8::Local<v8::String> GetExtend();
36+
static v8::Local<v8::String> GetNullObject();
37+
static v8::Local<v8::String> GetNullNodeName();
3638
static v8::Local<v8::String> GetIsPrototypeImplementationObject();
3739
static v8::Local<v8::String> GetNativeException();
3840
static v8::Local<v8::String> GetStackTrace();
@@ -51,6 +53,8 @@ namespace tns
5153
static const std::string CLASS_IMPLEMENTATION_OBJECT;
5254
static const std::string DEBUG_NAME;
5355
static const std::string EXTEND;
56+
static const std::string NULL_OBJECT;
57+
static const std::string NULL_NODE_NAME;
5458
static const std::string IS_PROTOTYPE_IMPLEMENTATION_OBJECT;
5559
static const std::string NATIVE_EXCEPTION;
5660
static const std::string STACK_TRACE;
@@ -80,6 +84,8 @@ namespace tns
8084
static v8::Persistent<v8::String> *CLASS_IMPLEMENTATION_OBJECT_PERSISTENT;
8185
static v8::Persistent<v8::String> *DEBUG_NAME_PERSISTENT;
8286
static v8::Persistent<v8::String> *EXTEND_PERSISTENT;
87+
static v8::Persistent<v8::String> *NULL_OBJECT_PERSISTENT;
88+
static v8::Persistent<v8::String> *NULL_NODE_NAME_PERSISTENT;
8389
static v8::Persistent<v8::String> *IS_PROTOTYPE_IMPLEMENTATION_OBJECT_PERSISTENT;
8490
static v8::Persistent<v8::String> *NATIVE_EXCEPTION_PERSISTENT;
8591
static v8::Persistent<v8::String> *STACK_TRACE_PERSISTENT;

0 commit comments

Comments
 (0)