Skip to content

Commit 5817a40

Browse files
committed
handle array types
1 parent 0128b73 commit 5817a40

7 files changed

Lines changed: 181 additions & 66 deletions

File tree

examples/lucene/example.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,10 @@ function search(searcher, queryString) {
5151
var query = queryParser.parseSync(queryString);
5252
var topDocs = searcher.searchSync(query, 10);
5353

54-
console.log("Found " + topDocs.totalHits + " hits for query " + queryString + ".")
54+
console.log("Found " + topDocs.totalHits + " hits for query " + queryString + ".");
55+
var scoreDocs = topDocs.scoreDocs;
5556
for(var i=0; i<topDocs.totalHits; i++) {
56-
var docId = topDocs.scoreDocs[i].doc;
57+
var docId = scoreDocs.doc;
5758
var doc = searcher.doc(docId);
5859
console.log((i + 1) + ". " + doc.get("title"));
5960
}

src/java.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,12 @@ v8::Handle<v8::Value> Java::createJVM(JavaVM** jvm, JNIEnv** env) {
489489

490490
// get field value
491491
jobject val = env->CallObjectMethod(field, field_get, NULL);
492-
492+
if(env->ExceptionOccurred()) {
493+
std::ostringstream errStr;
494+
errStr << "Could not get field " << fieldName.c_str() << " on class " << className.c_str();
495+
return ThrowException(javaExceptionToV8(env, errStr.str()));
496+
}
497+
493498
return scope.Close(javaToV8(self, env, resultType, val));
494499
}
495500

@@ -544,7 +549,15 @@ v8::Handle<v8::Value> Java::createJVM(JavaVM** jvm, JNIEnv** env) {
544549
jclass fieldClazz = env->FindClass("java/lang/reflect/Field");
545550
jmethodID field_set = env->GetMethodID(fieldClazz, "set", "(Ljava/lang/Object;Ljava/lang/Object;)V");
546551

552+
//printf("newValue: %s\n", javaObjectToString(env, newValue).c_str());
553+
547554
// set field value
548555
env->CallObjectMethod(field, field_set, NULL, newValue);
556+
if(env->ExceptionOccurred()) {
557+
std::ostringstream errStr;
558+
errStr << "Could not set field " << fieldName.c_str() << " on class " << className.c_str();
559+
return ThrowException(javaExceptionToV8(env, errStr.str()));
560+
}
561+
549562
return v8::Undefined();
550563
}

src/utils.cpp

Lines changed: 121 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -160,25 +160,44 @@ void javaDetachCurrentThread(JavaVM* jvm) {
160160
}
161161

162162
jvalueType javaGetType(JNIEnv *env, jclass type) {
163-
// TODO: has to be a better way
164-
std::string str = javaObjectToString(env, type);
165-
const char *typeStr = str.c_str();
166-
//printf("javaGetType: %s\n", typeStr);
167-
if(strcmp(typeStr, "int") == 0) {
168-
return TYPE_INT;
169-
} else if(strcmp(typeStr, "long") == 0) {
170-
return TYPE_LONG;
171-
} else if(strcmp(typeStr, "void") == 0) {
172-
return TYPE_VOID;
173-
} else if(strcmp(typeStr, "boolean") == 0) {
174-
return TYPE_BOOLEAN;
175-
} else if(strcmp(typeStr, "byte") == 0) {
176-
return TYPE_BYTE;
177-
} else if(strcmp(typeStr, "class java.lang.String") == 0) {
178-
return TYPE_STRING;
163+
jclass clazzClazz = env->FindClass("java/lang/Class");
164+
jmethodID class_isArray = env->GetMethodID(clazzClazz, "isArray", "()Z");
165+
jmethodID class_getComponentType = env->GetMethodID(clazzClazz, "getComponentType", "()Ljava/lang/Class;");
166+
167+
jboolean isArray = env->CallBooleanMethod(type, class_isArray);
168+
if(isArray) {
169+
jclass componentTypeClass = (jclass)env->CallObjectMethod(type, class_getComponentType);
170+
jvalueType componentType = javaGetType(env, componentTypeClass);
171+
switch(componentType) {
172+
case TYPE_INT: return TYPE_ARRAY_INT;
173+
case TYPE_LONG: return TYPE_ARRAY_LONG;
174+
case TYPE_OBJECT: return TYPE_ARRAY_OBJECT;
175+
case TYPE_STRING: return TYPE_ARRAY_STRING;
176+
case TYPE_BOOLEAN: return TYPE_ARRAY_BOOLEAN;
177+
case TYPE_BYTE: return TYPE_ARRAY_BYTE;
178+
default:
179+
return TYPE_ARRAY_OBJECT;
180+
}
181+
} else {
182+
// TODO: has to be a better way
183+
std::string str = javaObjectToString(env, type);
184+
const char *typeStr = str.c_str();
185+
//printf("javaGetType: %s\n", typeStr);
186+
if(strcmp(typeStr, "int") == 0) {
187+
return TYPE_INT;
188+
} else if(strcmp(typeStr, "long") == 0) {
189+
return TYPE_LONG;
190+
} else if(strcmp(typeStr, "void") == 0) {
191+
return TYPE_VOID;
192+
} else if(strcmp(typeStr, "boolean") == 0) {
193+
return TYPE_BOOLEAN;
194+
} else if(strcmp(typeStr, "byte") == 0) {
195+
return TYPE_BYTE;
196+
} else if(strcmp(typeStr, "class java.lang.String") == 0) {
197+
return TYPE_STRING;
198+
}
199+
return TYPE_OBJECT;
179200
}
180-
181-
return TYPE_OBJECT;
182201
}
183202

184203
jclass javaFindClass(JNIEnv* env, std::string className) {
@@ -197,8 +216,8 @@ jobject javaFindField(JNIEnv* env, jclass clazz, std::string fieldName) {
197216
jsize fieldCount = env->GetArrayLength(fieldObjects);
198217
for(jsize i=0; i<fieldCount; i++) {
199218
jobject field = env->GetObjectArrayElement(fieldObjects, i);
200-
std::string fieldName = javaToString(env, (jstring)env->CallObjectMethod(field, field_getName));
201-
if(strcmp(fieldName.c_str(), fieldName.c_str()) == 0) {
219+
std::string itFieldName = javaToString(env, (jstring)env->CallObjectMethod(field, field_getName));
220+
if(strcmp(itFieldName.c_str(), fieldName.c_str()) == 0) {
202221
return field;
203222
}
204223
}
@@ -211,6 +230,20 @@ jobject v8ToJava(JNIEnv* env, v8::Local<v8::Value> arg, jvalueType *methodArgTyp
211230
return NULL;
212231
}
213232

233+
if(arg->IsArray()) {
234+
v8::Local<v8::Array> array = v8::Array::Cast(*arg);
235+
uint32_t arraySize = array->Length();
236+
jclass objectClazz = env->FindClass("java/lang/Object");
237+
jobjectArray result = env->NewObjectArray(arraySize, objectClazz, NULL);
238+
for(uint32_t i=0; i<arraySize; i++) {
239+
jvalueType argType;
240+
jobject val = v8ToJava(env, array->Get(i), &argType);
241+
env->SetObjectArrayElement(result, i, val);
242+
}
243+
*methodArgType = TYPE_ARRAY_OBJECT;
244+
return result;
245+
}
246+
214247
if(arg->IsString()) {
215248
*methodArgType = TYPE_STRING;
216249
v8::String::AsciiValue val(arg->ToString());
@@ -301,44 +334,76 @@ v8::Handle<v8::Value> javaExceptionToV8(JNIEnv* env, const std::string& alternat
301334
return scope.Close(javaExceptionToV8(env, ex, alternateMessage));
302335
}
303336

337+
v8::Handle<v8::Value> javaArrayToV8(Java* java, JNIEnv* env, jvalueType itemType, jobjectArray objArray) {
338+
v8::HandleScope scope;
339+
340+
if(objArray == NULL) {
341+
return v8::Null();
342+
}
343+
344+
//printf("javaArrayToV8: %d %s\n", itemType, javaObjectToString(env, objArray).c_str());
345+
346+
jsize arraySize = env->GetArrayLength(objArray);
347+
//printf("array size: %d\n", arraySize);
348+
349+
v8::Handle<v8::Array> result = v8::Array::New(arraySize);
350+
for(jsize i=0; i<arraySize; i++) {
351+
jobject obj = env->GetObjectArrayElement(objArray, i);
352+
v8::Handle<v8::Value> item = javaToV8(java, env, itemType, obj);
353+
result->Set(i, item);
354+
}
355+
356+
return scope.Close(result);
357+
}
358+
304359
v8::Handle<v8::Value> javaToV8(Java* java, JNIEnv* env, jvalueType resultType, jobject obj) {
305-
v8::HandleScope scope;
360+
v8::HandleScope scope;
306361

307-
switch(resultType) {
308-
case TYPE_VOID:
309-
return v8::Undefined();
310-
case TYPE_BOOLEAN:
311-
{
312-
jclass booleanClazz = env->FindClass("java/lang/Boolean");
313-
jmethodID boolean_booleanValue = env->GetMethodID(booleanClazz, "booleanValue", "()Z");
314-
bool result = env->CallBooleanMethod(obj, boolean_booleanValue);
315-
return scope.Close(v8::Boolean::New(result));
316-
}
317-
case TYPE_BYTE:
318-
{
319-
jclass byteClazz = env->FindClass("java/lang/Byte");
320-
jmethodID byte_byteValue = env->GetMethodID(byteClazz, "byteValue", "()B");
321-
jbyte result = env->CallByteMethod(obj, byte_byteValue);
322-
return scope.Close(v8::Number::New(result));
323-
}
324-
case TYPE_LONG:
325-
{
326-
jclass longClazz = env->FindClass("java/lang/Long");
327-
jmethodID long_longValue = env->GetMethodID(longClazz, "longValue", "()J");
328-
jlong result = env->CallLongMethod(obj, long_longValue);
329-
return scope.Close(v8::Number::New(result));
330-
}
331-
case TYPE_INT:
332-
{
333-
jclass integerClazz = env->FindClass("java/lang/Integer");
334-
jmethodID integer_intValue = env->GetMethodID(integerClazz, "intValue", "()I");
335-
jint result = env->CallIntMethod(obj, integer_intValue);
336-
return scope.Close(v8::Integer::New(result));
337-
}
338-
case TYPE_OBJECT:
339-
return scope.Close(JavaObject::New(java, obj));
340-
case TYPE_STRING:
341-
return scope.Close(v8::String::New(javaObjectToString(env, obj).c_str()));
362+
//printf("javaToV8: %d %s\n", resultType, javaObjectToString(env, obj).c_str());
363+
364+
if((resultType & VALUE_TYPE_ARRAY) == VALUE_TYPE_ARRAY) {
365+
v8::Handle<v8::Value> result = javaArrayToV8(java, env, (jvalueType)(resultType & ~VALUE_TYPE_ARRAY), (jobjectArray)obj);
366+
return scope.Close(result);
367+
} else {
368+
switch(resultType) {
369+
case TYPE_VOID:
370+
return v8::Undefined();
371+
case TYPE_BOOLEAN:
372+
{
373+
jclass booleanClazz = env->FindClass("java/lang/Boolean");
374+
jmethodID boolean_booleanValue = env->GetMethodID(booleanClazz, "booleanValue", "()Z");
375+
bool result = env->CallBooleanMethod(obj, boolean_booleanValue);
376+
return scope.Close(v8::Boolean::New(result));
377+
}
378+
case TYPE_BYTE:
379+
{
380+
jclass byteClazz = env->FindClass("java/lang/Byte");
381+
jmethodID byte_byteValue = env->GetMethodID(byteClazz, "byteValue", "()B");
382+
jbyte result = env->CallByteMethod(obj, byte_byteValue);
383+
return scope.Close(v8::Number::New(result));
384+
}
385+
case TYPE_LONG:
386+
{
387+
jclass longClazz = env->FindClass("java/lang/Long");
388+
jmethodID long_longValue = env->GetMethodID(longClazz, "longValue", "()J");
389+
jlong result = env->CallLongMethod(obj, long_longValue);
390+
return scope.Close(v8::Number::New(result));
391+
}
392+
case TYPE_INT:
393+
{
394+
jclass integerClazz = env->FindClass("java/lang/Integer");
395+
jmethodID integer_intValue = env->GetMethodID(integerClazz, "intValue", "()I");
396+
jint result = env->CallIntMethod(obj, integer_intValue);
397+
return scope.Close(v8::Integer::New(result));
398+
}
399+
case TYPE_STRING:
400+
return scope.Close(v8::String::New(javaObjectToString(env, obj).c_str()));
401+
case TYPE_OBJECT:
402+
return scope.Close(JavaObject::New(java, obj));
403+
default:
404+
printf("unhandled type: 0x%03x\n", resultType);
405+
return scope.Close(JavaObject::New(java, obj));
406+
}
342407
}
343408
return v8::Undefined();
344409
}

src/utils.h

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,23 @@
1111
class Java;
1212

1313
typedef enum _jvalueType {
14-
TYPE_VOID = 1,
15-
TYPE_INT = 2,
16-
TYPE_LONG = 3,
17-
TYPE_OBJECT = 4,
18-
TYPE_STRING = 5,
19-
TYPE_BOOLEAN = 6,
20-
TYPE_BYTE = 7
14+
TYPE_VOID = 0x001,
15+
TYPE_INT = 0x002,
16+
TYPE_ARRAY_INT = 0x102,
17+
TYPE_LONG = 0x003,
18+
TYPE_ARRAY_LONG = 0x103,
19+
TYPE_OBJECT = 0x004,
20+
TYPE_ARRAY_OBJECT = 0x104,
21+
TYPE_STRING = 0x005,
22+
TYPE_ARRAY_STRING = 0x105,
23+
TYPE_BOOLEAN = 0x006,
24+
TYPE_ARRAY_BOOLEAN = 0x106,
25+
TYPE_BYTE = 0x007,
26+
TYPE_ARRAY_BYTE = 0x107
2127
} jvalueType;
2228

29+
#define VALUE_TYPE_ARRAY 0x100
30+
2331
std::list<jobject> javaReflectionGetMethods(JNIEnv *env, jclass clazz);
2432
std::list<jobject> javaReflectionGetConstructors(JNIEnv *env, jclass clazz);
2533
std::list<jobject> javaReflectionGetStaticMethods(JNIEnv *env, jclass clazz);
@@ -43,6 +51,7 @@ jarray v8ToJava(JNIEnv* env, const v8::Arguments& args, int start, int end, std:
4351
jobject v8ToJava(JNIEnv* env, v8::Local<v8::Value> arg, jvalueType *methodArgType);
4452
v8::Handle<v8::Value> javaExceptionToV8(JNIEnv* env, const std::string& alternateMessage);
4553
v8::Handle<v8::Value> javaExceptionToV8(JNIEnv* env, jthrowable ex, const std::string& alternateMessage);
54+
v8::Handle<v8::Value> javaArrayToV8(Java* java, JNIEnv* env, jvalueType itemType, jobjectArray objArray);
4655
v8::Handle<v8::Value> javaToV8(Java* java, JNIEnv* env, jvalueType resultType, jobject obj);
4756

4857
#endif

test/Test.class

57 Bytes
Binary file not shown.

test/Test.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
public class Test {
33
private int i;
44
public static int staticFieldInt = 42;
5+
public static Test[] staticArrayObjects = null;
56

67
public Test() {}
78
public Test(int i) { this.i = i; }

test/utils-types-test.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
var java = require("./testHelpers").java;
3+
4+
var nodeunit = require("nodeunit");
5+
var util = require("util");
6+
7+
exports['Utils - Types'] = nodeunit.testCase({
8+
"Array of Objects": function(test) {
9+
var val = java.getStaticFieldValue("Test", "staticArrayObjects");
10+
test.equal(null, val);
11+
12+
java.setStaticFieldValue("Test", "staticArrayObjects", java.newArray("Test", [
13+
java.newInstanceSync("Test", 1),
14+
java.newInstanceSync("Test", 2),
15+
java.newInstanceSync("Test", 3)
16+
]));
17+
18+
val = java.getStaticFieldValue("Test", "staticArrayObjects");
19+
test.ok(val);
20+
test.equal(val.length, 3);
21+
test.equal(val[0].getIntSync(), 1);
22+
test.equal(val[1].getIntSync(), 2);
23+
test.equal(val[2].getIntSync(), 3);
24+
test.done();
25+
}
26+
});

0 commit comments

Comments
 (0)