Skip to content

Commit 227fccd

Browse files
committed
added explicit null literals to aid in resolving methods with several overloads
1 parent 1116046 commit 227fccd

16 files changed

Lines changed: 303 additions & 6 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("isnull"));
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: 25 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,30 @@ bool JsArgToArrayConverter::ConvertArg(const Local<Value>& arg, int index)
287288

288289
case CastType::None:
289290
obj = objectManager->GetJavaObjectByJsObject(jsObj);
291+
292+
castValue = jsObj->GetHiddenValue(ConvertToV8String("node"));
293+
if(!castValue.IsEmpty()) {
294+
auto n = reinterpret_cast<MetadataNode*>(castValue.As<External>()->Value());
295+
auto type = (n != nullptr) ? n->GetName() : "";
296+
297+
jclass nullClazz = env.FindClass("com/tns/NullObject");
298+
jmethodID ctor = env.GetMethodID(nullClazz, "<init>", "(Ljava/lang/Class;)V");
299+
jclass clazzToNull = env.FindClass(type.c_str());
300+
jobject nullObjType = env.NewObject(nullClazz, ctor, clazzToNull);
301+
302+
if(nullObjType != nullptr)
303+
{
304+
SetConvertedObject(env, index, nullObjType, false);
305+
}
306+
else
307+
{
308+
SetConvertedObject(env, index, nullptr);
309+
}
310+
311+
success = true;
312+
return success;
313+
}
314+
290315
success = !obj.IsNull();
291316
if (success)
292317
{
@@ -300,7 +325,6 @@ bool JsArgToArrayConverter::ConvertArg(const Local<Value>& arg, int index)
300325

301326
default:
302327
throw NativeScriptException("Unsupported cast type");
303-
304328
}
305329
}
306330
else if (arg->IsUndefined() || arg->IsNull())

src/jni/MetadataNode.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,41 @@ 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 node = reinterpret_cast<MetadataNode*>(info.Data().As<External>()->Value());
285+
286+
DEBUG_WRITE("NullObjectAccessorGetterCallback node name: %s", node->GetName().c_str());
287+
288+
Local<Object> value = Object::New(isolate);
289+
auto k = ConvertToV8String("node");
290+
value->SetHiddenValue(k, External::New(isolate, node));
291+
value->SetHiddenValue(ConvertToV8String("isnull"), Boolean::New(isolate, true));
292+
// TODO: Pesho: Set .valueOf() callback to return null
293+
294+
info.GetReturnValue().Set(value);
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+
277312
void MetadataNode::FieldAccessorGetterCallback(Local<String> property, const PropertyCallbackInfo<Value>& info)
278313
{
279314
try
@@ -510,6 +545,11 @@ Local<Function> MetadataNode::SetMembersFromStaticMetadata(Isolate *isolate, Loc
510545
ctorFunction->SetAccessor(fieldName, FieldAccessorGetterCallback, FieldAccessorSetterCallback, fieldData, AccessControl::DEFAULT, PropertyAttribute::DontDelete);
511546
}
512547

548+
auto nullObjectName = V8StringConstants::GetNullObject();
549+
550+
Local<Value> nullObjectData = External::New(isolate, this);
551+
ctorFunction->SetAccessor(nullObjectName, NullObjectAccessorGetterCallback, nullptr, nullObjectData);
552+
513553
SetClassAccessor(ctorFunction);
514554

515555
return ctorFunction;
@@ -988,6 +1028,7 @@ void MetadataNode::MethodCallback(const v8::FunctionCallbackInfo<v8::Value>& inf
9881028

9891029
auto callbackData = reinterpret_cast<MethodCallbackData*>(e->Value());
9901030

1031+
// Number of arguments the method is invoked with
9911032
int argLength = info.Length();
9921033

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

10031044
className = &callbackData->node->m_name;
10041045

1046+
// Iterates through all methods and finds the best match based on the number of arguments
10051047
auto found = false;
10061048
for (auto& c : candidates)
10071049
{
10081050
found = c.paramCount == argLength;
10091051
if (found)
10101052
{
10111053
entry = &c;
1054+
DEBUG_WRITE("MetaDataEntry Method %s's signature is: %s", entry->name.c_str(), entry->sig.c_str());
10121055
break;
10131056
}
10141057
}
10151058

1059+
// Iterates through the parent class's methods to find a good match
10161060
if (!found)
10171061
{
10181062
callbackData = callbackData->parent;

src/jni/MetadataNode.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ 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+
213215
static void FieldAccessorGetterCallback(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info);
214216
static void FieldAccessorSetterCallback(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<void>& info);
215217
static void ClassAccessorGetterCallback(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info);

src/jni/MethodCache.cpp

Lines changed: 20 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,25 @@ 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+
string const IS_NULL_FIELD = "isnull";
108+
string const NODE_FIELD = "node";
109+
Local<Value> a = objVal->GetHiddenValue(ConvertToV8String(IS_NULL_FIELD));
110+
111+
if(!a.IsEmpty()) {
112+
auto node = objVal->GetHiddenValue(ConvertToV8String(NODE_FIELD));
113+
auto n = reinterpret_cast<MetadataNode*>(node.As<External>()->Value());
114+
115+
type = (n != nullptr) ? n->GetName() : "<unknown>";
116+
117+
DEBUG_WRITE("Parameter of type %s with NULL value is passed to the method.", type.c_str());
118+
return type;
119+
}
120+
}
121+
103122
if (value->IsArray() || value->IsArrayBuffer() || value->IsArrayBufferView() || value->IsTypedArray()
104123
|| value->IsFloat32Array() || value->IsFloat64Array()
105124
|| value->IsInt8Array() || value->IsInt16Array() || value->IsInt32Array()

src/jni/V8StringConstants.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ 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+
3142
Local<String> V8StringConstants::GetIsPrototypeImplementationObject()
3243
{
3344
auto isolate = Isolate::GetCurrent();
@@ -184,6 +195,7 @@ namespace tns
184195

185196
const string V8StringConstants::CLASS_IMPLEMENTATION_OBJECT = "t::ClassImplementationObject";
186197
const string V8StringConstants::EXTEND = "extend";
198+
const string V8StringConstants::NULL_OBJECT = "null";
187199
const string V8StringConstants::IS_PROTOTYPE_IMPLEMENTATION_OBJECT = "__isPrototypeImplementationObject";
188200
const string V8StringConstants::NATIVE_EXCEPTION = "nativeException";
189201
const string V8StringConstants::STACK_TRACE = "stackTrace";
@@ -209,6 +221,7 @@ namespace tns
209221
// TODO: These are not thread-safe!
210222
Persistent<String> *V8StringConstants::CLASS_IMPLEMENTATION_OBJECT_PERSISTENT;
211223
Persistent<String> *V8StringConstants::EXTEND_PERSISTENT;
224+
Persistent<String> *V8StringConstants::NULL_OBJECT_PERSISTENT;
212225
Persistent<String> *V8StringConstants::IS_PROTOTYPE_IMPLEMENTATION_OBJECT_PERSISTENT;
213226
Persistent<String> *V8StringConstants::NATIVE_EXCEPTION_PERSISTENT;
214227
Persistent<String> *V8StringConstants::STACK_TRACE_PERSISTENT;

src/jni/V8StringConstants.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ 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();
3637
static v8::Local<v8::String> GetIsPrototypeImplementationObject();
3738
static v8::Local<v8::String> GetNativeException();
3839
static v8::Local<v8::String> GetStackTrace();
@@ -51,6 +52,7 @@ namespace tns
5152
static const std::string CLASS_IMPLEMENTATION_OBJECT;
5253
static const std::string DEBUG_NAME;
5354
static const std::string EXTEND;
55+
static const std::string NULL_OBJECT;
5456
static const std::string IS_PROTOTYPE_IMPLEMENTATION_OBJECT;
5557
static const std::string NATIVE_EXCEPTION;
5658
static const std::string STACK_TRACE;
@@ -80,6 +82,7 @@ namespace tns
8082
static v8::Persistent<v8::String> *CLASS_IMPLEMENTATION_OBJECT_PERSISTENT;
8183
static v8::Persistent<v8::String> *DEBUG_NAME_PERSISTENT;
8284
static v8::Persistent<v8::String> *EXTEND_PERSISTENT;
85+
static v8::Persistent<v8::String> *NULL_OBJECT_PERSISTENT;
8386
static v8::Persistent<v8::String> *IS_PROTOTYPE_IMPLEMENTATION_OBJECT_PERSISTENT;
8487
static v8::Persistent<v8::String> *NATIVE_EXCEPTION_PERSISTENT;
8588
static v8::Persistent<v8::String> *STACK_TRACE_PERSISTENT;

src/src/com/tns/MethodResolver.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,10 @@ static void tryFindMatches(String methodName, ArrayList<Tuple<Method, Integer>>
172172
{
173173
if (args[i] != null)
174174
{
175-
Tuple<Boolean, Integer> res = isAssignableFrom(params[i], args[i].getClass());
175+
Class<?> argClass = args[i] instanceof NullObject ?
176+
((NullObject)args[i]).getNullObjectClass()
177+
: args[i].getClass();
178+
Tuple<Boolean, Integer> res = isAssignableFrom(params[i], argClass);
176179
success = res.x.booleanValue();
177180
dist += res.y;
178181
}

src/src/com/tns/NullObject.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.tns;
2+
3+
public final class NullObject
4+
{
5+
public NullObject(Class<?> clazz) {
6+
this.clazz = clazz;
7+
}
8+
9+
private final Class<?> clazz;
10+
11+
public final Class<?> getNullObjectClass() {
12+
return this.clazz;
13+
}
14+
}

test-app/assets/app/tests/testMethodResolution.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,10 @@ describe("Test Method Resolution", function () {
2121

2222
expect(value).toBe(2);
2323
});
24-
24+
25+
it("When_call_method_methodWithOverloadsWithOneArgument_with_java.lang.Object_argument", function () {
26+
__log("TEST: When_call_method_methodWithOverloadsWithOneArgument_with_java.lang.Object_argument");
27+
28+
29+
});
2530
});

0 commit comments

Comments
 (0)