Skip to content

Commit d7dcfbf

Browse files
committed
support for non-static public fields
1 parent 5817a40 commit d7dcfbf

File tree

9 files changed

+145
-12
lines changed

9 files changed

+145
-12
lines changed

examples/lucene/example.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ function search(searcher, queryString) {
5454
console.log("Found " + topDocs.totalHits + " hits for query " + queryString + ".");
5555
var scoreDocs = topDocs.scoreDocs;
5656
for(var i=0; i<topDocs.totalHits; i++) {
57-
var docId = scoreDocs.doc;
58-
var doc = searcher.doc(docId);
59-
console.log((i + 1) + ". " + doc.get("title"));
57+
var docId = scoreDocs[i].doc;
58+
var doc = searcher.docSync(docId);
59+
console.log((i + 1) + ". " + doc.getSync("title"));
6060
}
6161
}

src/javaObject.cpp

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "javaObject.h"
33
#include "java.h"
44
#include "utils.h"
5+
#include <sstream>
56

67
/*static*/ v8::Persistent<v8::FunctionTemplate> JavaObject::s_ct;
78

@@ -27,9 +28,9 @@
2728

2829
self->m_methods = javaReflectionGetMethods(env, self->m_class);
2930
jclass methodClazz = env->FindClass("java/lang/reflect/Method");
30-
jmethodID method_getNameMethod = env->GetMethodID(methodClazz, "getName", "()Ljava/lang/String;");
31+
jmethodID method_getName = env->GetMethodID(methodClazz, "getName", "()Ljava/lang/String;");
3132
for(std::list<jobject>::iterator it = self->m_methods.begin(); it != self->m_methods.end(); it++) {
32-
std::string methodNameStr = javaToString(env, (jstring)env->CallObjectMethod(*it, method_getNameMethod));
33+
std::string methodNameStr = javaToString(env, (jstring)env->CallObjectMethod(*it, method_getName));
3334

3435
v8::Handle<v8::String> methodName = v8::String::New(methodNameStr.c_str());
3536
v8::Local<v8::FunctionTemplate> methodCallTemplate = v8::FunctionTemplate::New(methodCall, methodName);
@@ -40,7 +41,15 @@
4041
javaObjectObj->Set(methodNameSync, methodCallSyncTemplate->GetFunction());
4142
}
4243

43-
// TODO: add public field support
44+
self->m_fields = javaReflectionGetFields(env, self->m_class);
45+
jclass fieldClazz = env->FindClass("java/lang/reflect/Field");
46+
jmethodID field_getName = env->GetMethodID(fieldClazz, "getName", "()Ljava/lang/String;");
47+
for(std::list<jobject>::iterator it = self->m_fields.begin(); it != self->m_fields.end(); it++) {
48+
std::string fieldNameStr = javaToString(env, (jstring)env->CallObjectMethod(*it, field_getName));
49+
50+
v8::Handle<v8::String> fieldName = v8::String::New(fieldNameStr.c_str());
51+
javaObjectObj->SetAccessor(fieldName, fieldGetter, fieldSetter);
52+
}
4453

4554
return scope.Close(javaObjectObj);
4655
}
@@ -110,3 +119,68 @@ JavaObject::~JavaObject() {
110119
delete baton;
111120
return scope.Close(result);;
112121
}
122+
123+
/*static*/ v8::Handle<v8::Value> JavaObject::fieldGetter(v8::Local<v8::String> property, const v8::AccessorInfo& info) {
124+
v8::HandleScope scope;
125+
JavaObject* self = node::ObjectWrap::Unwrap<JavaObject>(info.This());
126+
JNIEnv *env = self->m_java->getJavaEnv();
127+
128+
v8::String::AsciiValue propertyStr(property);
129+
jobject field = javaFindField(env, self->m_class, *propertyStr);
130+
if(field == NULL) {
131+
std::ostringstream errStr;
132+
errStr << "Could not find field " << *propertyStr;
133+
return ThrowException(javaExceptionToV8(env, errStr.str()));
134+
}
135+
136+
jclass fieldClazz = env->FindClass("java/lang/reflect/Field");
137+
jmethodID field_get = env->GetMethodID(fieldClazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
138+
jmethodID field_getType = env->GetMethodID(fieldClazz, "getType", "()Ljava/lang/Class;");
139+
140+
// get field type
141+
jclass fieldTypeClazz = (jclass)env->CallObjectMethod(field, field_getType);
142+
jvalueType resultType = javaGetType(env, fieldTypeClazz);
143+
144+
// get field value
145+
jobject val = env->CallObjectMethod(field, field_get, self->m_obj);
146+
if(env->ExceptionOccurred()) {
147+
std::ostringstream errStr;
148+
errStr << "Could not get field " << *propertyStr;
149+
return ThrowException(javaExceptionToV8(env, errStr.str()));
150+
}
151+
152+
return scope.Close(javaToV8(self->m_java, env, resultType, val));
153+
}
154+
155+
/*static*/ void JavaObject::fieldSetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo& info) {
156+
v8::HandleScope scope;
157+
JavaObject* self = node::ObjectWrap::Unwrap<JavaObject>(info.This());
158+
JNIEnv *env = self->m_java->getJavaEnv();
159+
160+
jvalueType methodArgType;
161+
jobject newValue = v8ToJava(env, value, &methodArgType);
162+
163+
v8::String::AsciiValue propertyStr(property);
164+
jobject field = javaFindField(env, self->m_class, *propertyStr);
165+
if(field == NULL) {
166+
std::ostringstream errStr;
167+
errStr << "Could not find field " << *propertyStr;
168+
ThrowException(javaExceptionToV8(env, errStr.str()));
169+
return;
170+
}
171+
172+
jclass fieldClazz = env->FindClass("java/lang/reflect/Field");
173+
jmethodID field_set = env->GetMethodID(fieldClazz, "set", "(Ljava/lang/Object;Ljava/lang/Object;)V");
174+
175+
//printf("newValue: %s\n", javaObjectToString(env, newValue).c_str());
176+
177+
// set field value
178+
env->CallObjectMethod(field, field_set, self->m_obj, newValue);
179+
if(env->ExceptionOccurred()) {
180+
std::ostringstream errStr;
181+
errStr << "Could not set field " << *propertyStr;
182+
ThrowException(javaExceptionToV8(env, errStr.str()));
183+
return;
184+
}
185+
}
186+

src/javaObject.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,15 @@ class JavaObject : public node::ObjectWrap {
2525
~JavaObject();
2626
static v8::Handle<v8::Value> methodCall(const v8::Arguments& args);
2727
static v8::Handle<v8::Value> methodCallSync(const v8::Arguments& args);
28+
static v8::Handle<v8::Value> fieldGetter(v8::Local<v8::String> property, const v8::AccessorInfo& info);
29+
static void fieldSetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo& info);
2830

2931
static v8::Persistent<v8::FunctionTemplate> s_ct;
3032
Java* m_java;
3133
jobject m_obj;
3234
jclass m_class;
3335
std::list<jobject> m_methods;
36+
std::list<jobject> m_fields;
3437
};
3538

3639
#endif

src/utils.cpp

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,47 @@
66
#include "javaObject.h"
77
#include "java.h"
88

9+
#define MODIFIER_STATIC 9
10+
911
std::list<jobject> javaReflectionGetMethods(JNIEnv *env, jclass clazz) {
1012
std::list<jobject> results;
1113

1214
jclass clazzclazz = env->GetObjectClass(clazz);
13-
jmethodID methodId = env->GetMethodID(clazzclazz, "getMethods", "()[Ljava/lang/reflect/Method;");
14-
// TODO: filter out static and prive methods
15-
jobjectArray methodObjects = (jobjectArray)env->CallObjectMethod(clazz, methodId);
15+
jmethodID clazz_getMethods = env->GetMethodID(clazzclazz, "getMethods", "()[Ljava/lang/reflect/Method;");
16+
jclass methodClazz = env->FindClass("java/lang/reflect/Method");
17+
jmethodID method_getModifiers = env->GetMethodID(methodClazz, "getModifiers", "()I");
18+
19+
jobjectArray methodObjects = (jobjectArray)env->CallObjectMethod(clazz, clazz_getMethods);
1620
jsize methodCount = env->GetArrayLength(methodObjects);
1721
for(jsize i=0; i<methodCount; i++) {
18-
jobject obj = env->GetObjectArrayElement(methodObjects, i);
19-
results.push_back(obj);
22+
jobject method = env->GetObjectArrayElement(methodObjects, i);
23+
jint methodModifiers = env->CallIntMethod(method, method_getModifiers);
24+
if((methodModifiers & MODIFIER_STATIC) == MODIFIER_STATIC) {
25+
continue;
26+
}
27+
results.push_back(method);
28+
}
29+
30+
return results;
31+
}
32+
33+
std::list<jobject> javaReflectionGetFields(JNIEnv *env, jclass clazz) {
34+
std::list<jobject> results;
35+
36+
jclass clazzclazz = env->GetObjectClass(clazz);
37+
jmethodID clazz_getFields = env->GetMethodID(clazzclazz, "getFields", "()[Ljava/lang/reflect/Field;");
38+
jclass fieldClazz = env->FindClass("java/lang/reflect/Field");
39+
jmethodID field_getModifiers = env->GetMethodID(fieldClazz, "getModifiers", "()I");
40+
41+
jobjectArray fieldObjects = (jobjectArray)env->CallObjectMethod(clazz, clazz_getFields);
42+
jsize fieldCount = env->GetArrayLength(fieldObjects);
43+
for(jsize i=0; i<fieldCount; i++) {
44+
jobject field = env->GetObjectArrayElement(fieldObjects, i);
45+
jint fieldModifiers = env->CallIntMethod(field, field_getModifiers);
46+
if((fieldModifiers & MODIFIER_STATIC) == MODIFIER_STATIC) {
47+
continue;
48+
}
49+
results.push_back(field);
2050
}
2151

2252
return results;
@@ -226,7 +256,7 @@ jobject javaFindField(JNIEnv* env, jclass clazz, std::string fieldName) {
226256
}
227257

228258
jobject v8ToJava(JNIEnv* env, v8::Local<v8::Value> arg, jvalueType *methodArgType) {
229-
if(arg->IsNull()) {
259+
if(arg->IsNull() || arg->IsUndefined()) {
230260
return NULL;
231261
}
232262

src/utils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ typedef enum _jvalueType {
3131
std::list<jobject> javaReflectionGetMethods(JNIEnv *env, jclass clazz);
3232
std::list<jobject> javaReflectionGetConstructors(JNIEnv *env, jclass clazz);
3333
std::list<jobject> javaReflectionGetStaticMethods(JNIEnv *env, jclass clazz);
34+
std::list<jobject> javaReflectionGetFields(JNIEnv *env, jclass clazz);
3435
std::string javaToString(JNIEnv *env, jstring str);
3536
std::string javaObjectToString(JNIEnv *env, jobject obj);
3637
jobject javaFindBestMatchingMethod(

test/Test.class

61 Bytes
Binary file not shown.

test/Test.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
public class Test {
33
private int i;
4+
public int nonstaticInt = 42;
45
public static int staticFieldInt = 42;
56
public static Test[] staticArrayObjects = null;
67

test/java-newInstance-test.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ exports['Java - New Instance'] = nodeunit.testCase({
99
java.newInstance("Test", function(err, result) {
1010
test.ok(result);
1111
test.equal(result.getClassSync().toStringSync(), "class Test");
12+
test.ok(result.getInt);
13+
test.ok(result.getIntSync);
14+
test.ok(!result.staticMethod);
15+
test.ok(!result.staticMethodSync);
16+
test.equal(result.nonstaticInt, 42);
1217
test.done();
1318
});
1419
},

test/javaObject-test.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
var java = require("./testHelpers").java;
3+
4+
var nodeunit = require("nodeunit");
5+
var util = require("util");
6+
7+
exports['Java Object'] = nodeunit.testCase({
8+
setUp: function(callback) {
9+
this.testObj = java.newInstanceSync("Test");
10+
callback();
11+
},
12+
13+
"field": function(test) {
14+
test.equal(this.testObj.nonstaticInt, 42);
15+
this.testObj.nonstaticInt = 112;
16+
test.equal(this.testObj.nonstaticInt, 112);
17+
test.done();
18+
},
19+
});

0 commit comments

Comments
 (0)