Skip to content

Commit bafec88

Browse files
committed
better method overload matching
1 parent 06877f6 commit bafec88

16 files changed

Lines changed: 118 additions & 162 deletions

commons-lang3-node-java.jar

320 KB
Binary file not shown.

jarjar.rule

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rule org.apache.commons.lang3.** com.nearinfinity.org.apache.commons.lang3.@1

lib/nodeJavaBridge.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11

22
var bindings = require("../build/Release/nodejavabridge_bindings");
33

4-
module.exports = new bindings.Java();
4+
var java = module.exports = new bindings.Java();
5+
java.classpath.push(__dirname + "/../commons-lang3-node-java.jar");

src/java.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,8 @@ v8::Handle<v8::Value> Java::createJVM(JavaVM** jvm, JNIEnv** env) {
144144
v8::Function::Cast(*callback)->Call(v8::Context::GetCurrent()->Global(), 2, argv);
145145
return v8::Undefined();
146146
}
147-
std::list<jobject> constructors = javaReflectionGetConstructors(env, clazz);
148-
jobject method = javaFindBestMatchingConstructor(env, constructors, methodArgs);
147+
148+
jobject method = javaFindConstructor(env, clazz, methodArgs);
149149
if(method == NULL) {
150150
std::ostringstream errStr;
151151
errStr << "Could not find constructor";
@@ -200,8 +200,8 @@ v8::Handle<v8::Value> Java::createJVM(JavaVM** jvm, JNIEnv** env) {
200200
errStr << "Could not create class " << className.c_str();
201201
return ThrowException(javaExceptionToV8(env, errStr.str()));
202202
}
203-
std::list<jobject> constructors = javaReflectionGetConstructors(env, clazz);
204-
jobject method = javaFindBestMatchingConstructor(env, constructors, methodArgs);
203+
204+
jobject method = javaFindConstructor(env, clazz, methodArgs);
205205
if(method == NULL) {
206206
std::ostringstream errStr;
207207
errStr << "Could not find constructor";
@@ -274,8 +274,9 @@ v8::Handle<v8::Value> Java::createJVM(JavaVM** jvm, JNIEnv** env) {
274274
v8::Function::Cast(*callback)->Call(v8::Context::GetCurrent()->Global(), 2, argv);
275275
return v8::Undefined();
276276
}
277-
std::list<jobject> staticMethods = javaReflectionGetStaticMethods(env, clazz);
278-
jobject method = javaFindBestMatchingMethod(env, staticMethods, methodName.c_str(), methodArgs);
277+
278+
// find method
279+
jobject method = javaFindMethod(env, clazz, methodName, methodArgs);
279280
if(method == NULL) {
280281
std::ostringstream errStr;
281282
errStr << "Could not find method \"" << methodName.c_str() << "\"";
@@ -338,8 +339,9 @@ v8::Handle<v8::Value> Java::createJVM(JavaVM** jvm, JNIEnv** env) {
338339
errStr << "Could not create class " << className.c_str();
339340
return ThrowException(javaExceptionToV8(env, errStr.str()));
340341
}
341-
std::list<jobject> staticMethods = javaReflectionGetStaticMethods(env, clazz);
342-
jobject method = javaFindBestMatchingMethod(env, staticMethods, methodName.c_str(), methodArgs);
342+
343+
// find method
344+
jobject method = javaFindMethod(env, clazz, methodName, methodArgs);
343345
if(method == NULL) {
344346
std::ostringstream errStr;
345347
errStr << "Could not find method \"" << methodName.c_str() << "\"";

src/javaObject.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@
2626

2727
JNIEnv *env = self->m_java->getJavaEnv();
2828

29-
self->m_methods = javaReflectionGetMethods(env, self->m_class);
29+
std::list<jobject> methods = javaReflectionGetMethods(env, self->m_class);
3030
jclass methodClazz = env->FindClass("java/lang/reflect/Method");
3131
jmethodID method_getName = env->GetMethodID(methodClazz, "getName", "()Ljava/lang/String;");
32-
for(std::list<jobject>::iterator it = self->m_methods.begin(); it != self->m_methods.end(); it++) {
32+
for(std::list<jobject>::iterator it = methods.begin(); it != methods.end(); it++) {
3333
std::string methodNameStr = javaToString(env, (jstring)env->CallObjectMethod(*it, method_getName));
3434

3535
v8::Handle<v8::String> methodName = v8::String::New(methodNameStr.c_str());
@@ -71,6 +71,7 @@ JavaObject::~JavaObject() {
7171
bool callbackProvided;
7272

7373
v8::String::AsciiValue methodName(args.Data());
74+
std::string methodNameStr = *methodName;
7475

7576
int argsEnd = args.Length();
7677

@@ -87,9 +88,18 @@ JavaObject::~JavaObject() {
8788

8889
jobjectArray methodArgs = v8ToJava(env, args, 0, argsEnd);
8990

90-
jobject method = javaFindBestMatchingMethod(env, self->m_methods, *methodName, methodArgs);
91+
jobject method = javaFindMethod(env, self->m_class, methodNameStr, methodArgs);
9192
if(method == NULL) {
92-
return v8::Undefined(); // TODO: callback with error
93+
std::ostringstream errStr;
94+
errStr << "Could not call method " << methodNameStr;
95+
v8::Handle<v8::Value> error = javaExceptionToV8(env, errStr.str());
96+
97+
v8::Handle<v8::Value> argv[2];
98+
argv[0] = error;
99+
argv[1] = v8::Undefined();
100+
101+
v8::Function::Cast(*callback)->Call(v8::Context::GetCurrent()->Global(), 2, argv);
102+
return v8::Undefined();
93103
}
94104

95105
// run
@@ -111,10 +121,11 @@ JavaObject::~JavaObject() {
111121
JNIEnv *env = self->m_java->getJavaEnv();
112122

113123
v8::String::AsciiValue methodName(args.Data());
124+
std::string methodNameStr = *methodName;
114125

115126
jobjectArray methodArgs = v8ToJava(env, args, 0, args.Length());
116127

117-
jobject method = javaFindBestMatchingMethod(env, self->m_methods, *methodName, methodArgs);
128+
jobject method = javaFindMethod(env, self->m_class, methodNameStr, methodArgs);
118129
if(method == NULL) {
119130
return v8::Undefined();
120131
}

src/javaObject.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class JavaObject : public node::ObjectWrap {
1616
static v8::Local<v8::Object> New(Java* java, jobject obj);
1717

1818
jobject getObject() { return m_obj; }
19-
19+
2020
void Ref() { node::ObjectWrap::Ref(); }
2121
void Unref() { node::ObjectWrap::Unref(); }
2222

@@ -32,7 +32,6 @@ class JavaObject : public node::ObjectWrap {
3232
Java* m_java;
3333
jobject m_obj;
3434
jclass m_class;
35-
std::list<jobject> m_methods;
3635
std::list<jobject> m_fields;
3736
};
3837

src/utils.cpp

Lines changed: 33 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -52,37 +52,6 @@ std::list<jobject> javaReflectionGetFields(JNIEnv *env, jclass clazz) {
5252
return results;
5353
}
5454

55-
std::list<jobject> javaReflectionGetStaticMethods(JNIEnv *env, jclass clazz) {
56-
std::list<jobject> results;
57-
58-
jclass clazzclazz = env->GetObjectClass(clazz);
59-
jmethodID methodId = env->GetMethodID(clazzclazz, "getDeclaredMethods", "()[Ljava/lang/reflect/Method;");
60-
// TODO: filter out instance and prive methods
61-
jobjectArray methodObjects = (jobjectArray)env->CallObjectMethod(clazz, methodId);
62-
jsize methodCount = env->GetArrayLength(methodObjects);
63-
for(jsize i=0; i<methodCount; i++) {
64-
jobject obj = env->GetObjectArrayElement(methodObjects, i);
65-
results.push_back(obj);
66-
}
67-
68-
return results;
69-
}
70-
71-
std::list<jobject> javaReflectionGetConstructors(JNIEnv *env, jclass clazz) {
72-
std::list<jobject> results;
73-
74-
jclass clazzclazz = env->GetObjectClass(clazz);
75-
jmethodID methodId = env->GetMethodID(clazzclazz, "getConstructors", "()[Ljava/lang/reflect/Constructor;");
76-
jobjectArray methodObjects = (jobjectArray)env->CallObjectMethod(clazz, methodId);
77-
jsize methodCount = env->GetArrayLength(methodObjects);
78-
for(jsize i=0; i<methodCount; i++) {
79-
jobject obj = env->GetObjectArrayElement(methodObjects, i);
80-
results.push_back(obj);
81-
}
82-
83-
return results;
84-
}
85-
8655
std::string javaToString(JNIEnv *env, jstring str) {
8756
const char* chars = env->GetStringUTFChars(str, NULL);
8857
std::string results = chars;
@@ -100,103 +69,6 @@ std::string javaObjectToString(JNIEnv *env, jobject obj) {
10069
return javaToString(env, result);
10170
}
10271

103-
jobject javaFindBestMatchingMethod(
104-
JNIEnv *env,
105-
std::list<jobject>& methods,
106-
const char *methodName,
107-
jobjectArray args) {
108-
109-
jsize argsSize = env->GetArrayLength(args);
110-
111-
std::list<jobject> possibleMatches;
112-
jclass methodClazz = env->FindClass("java/lang/reflect/Method");
113-
jmethodID method_getNameMethod = env->GetMethodID(methodClazz, "getName", "()Ljava/lang/String;");
114-
jmethodID method_getParameterTypes = env->GetMethodID(methodClazz, "getParameterTypes", "()[Ljava/lang/Class;");
115-
116-
for(std::list<jobject>::iterator it = methods.begin(); it != methods.end(); it++) {
117-
std::string itMethodName = javaToString(env, (jstring)env->CallObjectMethod(*it, method_getNameMethod));
118-
if(itMethodName == methodName) {
119-
jobjectArray parameters = (jobjectArray)env->CallObjectMethod(*it, method_getParameterTypes);
120-
if(env->GetArrayLength(parameters) == argsSize) {
121-
possibleMatches.push_back(*it);
122-
}
123-
}
124-
}
125-
126-
if(possibleMatches.size() == 0) {
127-
return NULL;
128-
}
129-
if(possibleMatches.size() == 1) {
130-
return possibleMatches.front();
131-
} else {
132-
// second pass to check arguments
133-
for(std::list<jobject>::iterator it = possibleMatches.begin(); it != possibleMatches.end(); it++) {
134-
jobjectArray possibleMatchArgs = (jobjectArray)env->CallObjectMethod(*it, method_getParameterTypes);
135-
jsize i;
136-
for(i=0; i<argsSize; i++) {
137-
jobject arg = env->GetObjectArrayElement(args, i);
138-
//jclass argClass = env->GetObjectClass(arg);
139-
jclass possibleMatchArgClass = (jclass)env->GetObjectArrayElement(possibleMatchArgs, i);
140-
jboolean isAssignableFrom = env->IsInstanceOf(arg, possibleMatchArgClass);
141-
//printf("match\n\t%s\n\t%s\n\t%d\n", javaObjectToString(env,argClass).c_str(), javaObjectToString(env,possibleMatchArgClass).c_str(), isAssignableFrom);
142-
if(!isAssignableFrom)
143-
break;
144-
}
145-
if(i == argsSize) {
146-
return *it;
147-
}
148-
}
149-
150-
/*
151-
printf("javaFindBestMatchingMethod: multiple matches (choosing the first)\n");
152-
for(std::list<jobject>::iterator it = possibleMatches.begin(); it != possibleMatches.end(); it++) {
153-
printf(" %s\n", javaObjectToString(env, *it).c_str());
154-
}
155-
*/
156-
157-
return possibleMatches.front();
158-
}
159-
160-
return NULL;
161-
}
162-
163-
jobject javaFindBestMatchingConstructor(
164-
JNIEnv *env,
165-
std::list<jobject>& constructors,
166-
jobjectArray args) {
167-
168-
jsize argsSize = env->GetArrayLength(args);
169-
170-
std::list<jobject> possibleMatches;
171-
jclass constructorClazz = env->FindClass("java/lang/reflect/Constructor");
172-
jmethodID constructor_getParameterTypes = env->GetMethodID(constructorClazz, "getParameterTypes", "()[Ljava/lang/Class;");
173-
174-
for(std::list<jobject>::iterator it = constructors.begin(); it != constructors.end(); it++) {
175-
jarray parameters = (jarray)env->CallObjectMethod(*it, constructor_getParameterTypes);
176-
if(env->GetArrayLength(parameters) == argsSize) {
177-
possibleMatches.push_back(*it);
178-
}
179-
}
180-
181-
if(possibleMatches.size() == 0) {
182-
return NULL;
183-
}
184-
if(possibleMatches.size() == 1) {
185-
return possibleMatches.front();
186-
} else {
187-
// TODO: argument match
188-
/*
189-
printf("javaFindBestMatchingConstructor: multiple matches (choosing the first)\n");
190-
for(std::list<jobject>::iterator it = possibleMatches.begin(); it != possibleMatches.end(); it++) {
191-
printf(" %s\n", javaObjectToString(env, *it).c_str());
192-
}
193-
*/
194-
return possibleMatches.front();
195-
}
196-
197-
return NULL;
198-
}
199-
20072
JNIEnv* javaAttachCurrentThread(JavaVM* jvm) {
20173
JNIEnv* env;
20274
JavaVMAttachArgs attachArgs;
@@ -372,6 +244,7 @@ v8::Handle<v8::Value> javaExceptionToV8(JNIEnv* env, jthrowable ex, const std::s
372244
v8::Handle<v8::Value> javaExceptionToV8(JNIEnv* env, const std::string& alternateMessage) {
373245
v8::HandleScope scope;
374246
jthrowable ex = env->ExceptionOccurred();
247+
env->ExceptionClear();
375248
return scope.Close(javaExceptionToV8(env, ex, alternateMessage));
376249
}
377250

@@ -447,4 +320,35 @@ v8::Handle<v8::Value> javaToV8(Java* java, JNIEnv* env, jvalueType resultType, j
447320
}
448321
}
449322
return v8::Undefined();
450-
}
323+
}
324+
325+
jobjectArray javaObjectArrayToClasses(JNIEnv *env, jobjectArray objs) {
326+
jclass clazzClazz = env->FindClass("java/lang/Class");
327+
jsize objsLength = env->GetArrayLength(objs);
328+
jobjectArray results = env->NewObjectArray(objsLength, clazzClazz, NULL);
329+
for(jsize i=0; i<objsLength; i++) {
330+
jclass objClazz = env->GetObjectClass(env->GetObjectArrayElement(objs, i));
331+
env->SetObjectArrayElement(results, i, objClazz);
332+
}
333+
return results;
334+
}
335+
336+
jobject javaFindMethod(JNIEnv *env, jclass clazz, std::string& methodName, jobjectArray methodArgs) {
337+
jclass methodUtilsClazz = env->FindClass("com/nearinfinity/org/apache/commons/lang3/reflect/MethodUtils");
338+
jmethodID methodUtils_getMatchingAccessibleMethod = env->GetStaticMethodID(methodUtilsClazz, "getMatchingAccessibleMethod", "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");
339+
const char *methodNameCStr = methodName.c_str();
340+
jstring methodNameJavaStr = env->NewStringUTF(methodNameCStr);
341+
jobjectArray methodArgClasses = javaObjectArrayToClasses(env, methodArgs);
342+
jobject method = env->CallStaticObjectMethod(methodUtilsClazz, methodUtils_getMatchingAccessibleMethod, clazz, methodNameJavaStr, methodArgClasses);
343+
344+
return method;
345+
}
346+
347+
jobject javaFindConstructor(JNIEnv *env, jclass clazz, jobjectArray methodArgs) {
348+
jclass constructorUtilsClazz = env->FindClass("com/nearinfinity/org/apache/commons/lang3/reflect/ConstructorUtils");
349+
jmethodID constructorUtils_getMatchingAccessibleConstructor = env->GetStaticMethodID(constructorUtilsClazz, "getMatchingAccessibleConstructor", "(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/reflect/Constructor;");
350+
jobjectArray methodArgClasses = javaObjectArrayToClasses(env, methodArgs);
351+
jobject method = env->CallStaticObjectMethod(constructorUtilsClazz, constructorUtils_getMatchingAccessibleConstructor, clazz, methodArgClasses);
352+
353+
return method;
354+
}

src/utils.h

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,9 @@ typedef enum _jvalueType {
3030
#define VALUE_TYPE_ARRAY 0x100
3131

3232
std::list<jobject> javaReflectionGetMethods(JNIEnv *env, jclass clazz);
33-
std::list<jobject> javaReflectionGetConstructors(JNIEnv *env, jclass clazz);
34-
std::list<jobject> javaReflectionGetStaticMethods(JNIEnv *env, jclass clazz);
3533
std::list<jobject> javaReflectionGetFields(JNIEnv *env, jclass clazz);
3634
std::string javaToString(JNIEnv *env, jstring str);
3735
std::string javaObjectToString(JNIEnv *env, jobject obj);
38-
jobject javaFindBestMatchingMethod(
39-
JNIEnv *env,
40-
std::list<jobject>& methods,
41-
const char *methodName,
42-
jobjectArray args);
43-
jobject javaFindBestMatchingConstructor(
44-
JNIEnv *env,
45-
std::list<jobject>& constructors,
46-
jobjectArray args);
4736
JNIEnv* javaAttachCurrentThread(JavaVM* jvm);
4837
void javaDetachCurrentThread(JavaVM* jvm);
4938
jvalueType javaGetType(JNIEnv *env, jclass type);
@@ -55,5 +44,8 @@ v8::Handle<v8::Value> javaExceptionToV8(JNIEnv* env, const std::string& alternat
5544
v8::Handle<v8::Value> javaExceptionToV8(JNIEnv* env, jthrowable ex, const std::string& alternateMessage);
5645
v8::Handle<v8::Value> javaArrayToV8(Java* java, JNIEnv* env, jvalueType itemType, jobjectArray objArray);
5746
v8::Handle<v8::Value> javaToV8(Java* java, JNIEnv* env, jvalueType resultType, jobject obj);
47+
jobjectArray javaObjectArrayToClasses(JNIEnv *env, jobjectArray objs);
48+
jobject javaFindMethod(JNIEnv *env, jclass clazz, std::string& methodName, jobjectArray methodArgs);
49+
jobject javaFindConstructor(JNIEnv *env, jclass clazz, jobjectArray methodArgs);
5850

5951
#endif

test/Test$SubClass.class

318 Bytes
Binary file not shown.

test/Test$SuperClass.class

302 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)