Skip to content

Commit 191cbc9

Browse files
committed
added set static field
added unit tests for static fields
1 parent 78f857b commit 191cbc9

10 files changed

Lines changed: 152 additions & 58 deletions

File tree

src/java.cpp

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
NODE_SET_PROTOTYPE_METHOD(s_ct, "newArray", newArray);
2323
NODE_SET_PROTOTYPE_METHOD(s_ct, "newByte", newByte);
2424
NODE_SET_PROTOTYPE_METHOD(s_ct, "getStaticFieldValue", getStaticFieldValue);
25+
NODE_SET_PROTOTYPE_METHOD(s_ct, "setStaticFieldValue", setStaticFieldValue);
2526

2627
target->Set(v8::String::NewSymbol("Java"), s_ct->GetFunction());
2728
}
@@ -121,7 +122,7 @@ v8::Handle<v8::Value> Java::createJVM(JavaVM** jvm, JNIEnv** env) {
121122
callback = v8::Null();
122123
}
123124

124-
std::list<int> methodArgTypes;
125+
std::list<jvalueType> methodArgTypes;
125126
jarray methodArgs = v8ToJava(env, args, 1, argsEnd, &methodArgTypes);
126127

127128
jclass clazz = javaFindClass(env, className);
@@ -179,7 +180,7 @@ v8::Handle<v8::Value> Java::createJVM(JavaVM** jvm, JNIEnv** env) {
179180
std::string className = *classNameVal;
180181
argsStart++;
181182

182-
std::list<int> methodArgTypes;
183+
std::list<jvalueType> methodArgTypes;
183184
jarray methodArgs = v8ToJava(env, args, argsStart, argsEnd, &methodArgTypes);
184185

185186
jclass clazz = javaFindClass(env, className);
@@ -244,7 +245,7 @@ v8::Handle<v8::Value> Java::createJVM(JavaVM** jvm, JNIEnv** env) {
244245
}
245246

246247
// build args
247-
std::list<int> methodArgTypes;
248+
std::list<jvalueType> methodArgTypes;
248249
jarray methodArgs = v8ToJava(env, args, 2, argsEnd, &methodArgTypes);
249250

250251
// find class and method
@@ -309,7 +310,7 @@ v8::Handle<v8::Value> Java::createJVM(JavaVM** jvm, JNIEnv** env) {
309310
std::string methodName = *methodNameVal;
310311

311312
// build args
312-
std::list<int> methodArgTypes;
313+
std::list<jvalueType> methodArgTypes;
313314
jarray methodArgs = v8ToJava(env, args, 2, argsEnd, &methodArgTypes);
314315

315316
// find class and method
@@ -366,7 +367,7 @@ v8::Handle<v8::Value> Java::createJVM(JavaVM** jvm, JNIEnv** env) {
366367
if(strcmp(className.c_str(), "byte") == 0) {
367368
results = env->NewByteArray(arrayObj->Length());
368369
for(uint32_t i=0; i<arrayObj->Length(); i++) {
369-
int methodArgType;
370+
jvalueType methodArgType;
370371
v8::Local<v8::Value> item = arrayObj->Get(i);
371372
jobject val = v8ToJava(env, item, &methodArgType);
372373
jclass byteClazz = env->FindClass("java/lang/Byte");
@@ -390,7 +391,7 @@ v8::Handle<v8::Value> Java::createJVM(JavaVM** jvm, JNIEnv** env) {
390391
results = env->NewObjectArray(arrayObj->Length(), clazz, NULL);
391392

392393
for(uint32_t i=0; i<arrayObj->Length(); i++) {
393-
int methodArgType;
394+
jvalueType methodArgType;
394395
v8::Local<v8::Value> item = arrayObj->Get(i);
395396
jobject val = v8ToJava(env, item, &methodArgType);
396397
env->SetObjectArrayElement((jobjectArray)results, i, val);
@@ -474,11 +475,72 @@ v8::Handle<v8::Value> Java::createJVM(JavaVM** jvm, JNIEnv** env) {
474475
return ThrowException(javaExceptionToV8(env, errStr.str()));
475476
}
476477

477-
// get field value
478478
jclass fieldClazz = env->FindClass("java/lang/reflect/Field");
479479
jmethodID field_get = env->GetMethodID(fieldClazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
480+
jmethodID field_getType = env->GetMethodID(fieldClazz, "getType", "()Ljava/lang/Class;");
481+
482+
// get field type
483+
jclass fieldTypeClazz = (jclass)env->CallObjectMethod(field, field_getType);
484+
jvalueType resultType = javaGetType(env, fieldTypeClazz);
485+
486+
// get field value
480487
jobject val = env->CallObjectMethod(field, field_get, NULL);
481488

482-
return scope.Close(JavaObject::New(self, val));
489+
return scope.Close(javaToV8(self, env, resultType, val));
483490
}
484491

492+
/*static*/ v8::Handle<v8::Value> Java::setStaticFieldValue(const v8::Arguments& args) {
493+
v8::HandleScope scope;
494+
Java* self = node::ObjectWrap::Unwrap<Java>(args.This());
495+
v8::Handle<v8::Value> ensureJvmResults = self->ensureJvm();
496+
if(!ensureJvmResults->IsUndefined()) {
497+
return ensureJvmResults;
498+
}
499+
JNIEnv* env = self->getJavaEnv();
500+
501+
// argument - className
502+
if(args.Length() < 1 || !args[0]->IsString()) {
503+
return ThrowException(v8::Exception::TypeError(v8::String::New("Argument 0 must be a string")));
504+
}
505+
v8::Local<v8::String> classNameObj = v8::Local<v8::String>::Cast(args[0]);
506+
v8::String::AsciiValue classNameVal(classNameObj);
507+
std::string className = *classNameVal;
508+
509+
// argument - field name
510+
if(args.Length() < 2 || !args[1]->IsString()) {
511+
return ThrowException(v8::Exception::TypeError(v8::String::New("Argument 1 must be a string")));
512+
}
513+
v8::Local<v8::String> fieldNameObj = v8::Local<v8::String>::Cast(args[1]);
514+
v8::String::AsciiValue fieldNameVal(fieldNameObj);
515+
std::string fieldName = *fieldNameVal;
516+
517+
// argument - new value
518+
if(args.Length() < 3) {
519+
return ThrowException(v8::Exception::TypeError(v8::String::New("setStaticFieldValue requires 3 arguments")));
520+
}
521+
jvalueType methodArgType;
522+
jobject newValue = v8ToJava(env, args[2], &methodArgType);
523+
524+
// find the class
525+
jclass clazz = javaFindClass(env, className);
526+
if(clazz == NULL) {
527+
std::ostringstream errStr;
528+
errStr << "Could not create class " << className.c_str();
529+
return ThrowException(javaExceptionToV8(env, errStr.str()));
530+
}
531+
532+
// get the field
533+
jobject field = javaFindField(env, clazz, fieldName);
534+
if(field == NULL) {
535+
std::ostringstream errStr;
536+
errStr << "Could not find field " << fieldName.c_str() << " on class " << className.c_str();
537+
return ThrowException(javaExceptionToV8(env, errStr.str()));
538+
}
539+
540+
jclass fieldClazz = env->FindClass("java/lang/reflect/Field");
541+
jmethodID field_set = env->GetMethodID(fieldClazz, "set", "(Ljava/lang/Object;Ljava/lang/Object;)V");
542+
543+
// set field value
544+
env->CallObjectMethod(field, field_set, NULL, newValue);
545+
return v8::Undefined();
546+
}

src/java.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class Java : public node::ObjectWrap {
2626
static v8::Handle<v8::Value> newArray(const v8::Arguments& args);
2727
static v8::Handle<v8::Value> newByte(const v8::Arguments& args);
2828
static v8::Handle<v8::Value> getStaticFieldValue(const v8::Arguments& args);
29+
static v8::Handle<v8::Value> setStaticFieldValue(const v8::Arguments& args);
2930
v8::Handle<v8::Value> ensureJvm();
3031

3132
static v8::Persistent<v8::FunctionTemplate> s_ct;

src/javaObject.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ JavaObject::~JavaObject() {
7373
callback = v8::Null();
7474
}
7575

76-
std::list<int> methodArgTypes;
76+
std::list<jvalueType> methodArgTypes;
7777
jarray methodArgs = v8ToJava(env, args, 0, argsEnd, &methodArgTypes);
7878

7979
jobject method = javaFindBestMatchingMethod(env, self->m_methods, *methodName, methodArgTypes);
@@ -95,7 +95,7 @@ JavaObject::~JavaObject() {
9595

9696
v8::String::AsciiValue methodName(args.Data());
9797

98-
std::list<int> methodArgTypes;
98+
std::list<jvalueType> methodArgTypes;
9999
jarray methodArgs = v8ToJava(env, args, 0, args.Length(), &methodArgTypes);
100100

101101
jobject method = javaFindBestMatchingMethod(env, self->m_methods, *methodName, methodArgTypes);

src/methodCallBaton.cpp

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -76,43 +76,7 @@ v8::Handle<v8::Value> MethodCallBaton::resultsToV8(JNIEnv *env) {
7676
return scope.Close(err);
7777
}
7878

79-
switch(m_resultType) {
80-
case TYPE_VOID:
81-
return v8::Undefined();
82-
case TYPE_BOOLEAN:
83-
{
84-
jclass booleanClazz = env->FindClass("java/lang/Boolean");
85-
jmethodID boolean_booleanValue = env->GetMethodID(booleanClazz, "booleanValue", "()Z");
86-
bool result = env->CallBooleanMethod(m_result, boolean_booleanValue);
87-
return scope.Close(v8::Boolean::New(result));
88-
}
89-
case TYPE_BYTE:
90-
{
91-
jclass byteClazz = env->FindClass("java/lang/Byte");
92-
jmethodID byte_byteValue = env->GetMethodID(byteClazz, "byteValue", "()B");
93-
jbyte result = env->CallByteMethod(m_result, byte_byteValue);
94-
return scope.Close(v8::Number::New(result));
95-
}
96-
case TYPE_LONG:
97-
{
98-
jclass longClazz = env->FindClass("java/lang/Long");
99-
jmethodID long_longValue = env->GetMethodID(longClazz, "longValue", "()J");
100-
jlong result = env->CallLongMethod(m_result, long_longValue);
101-
return scope.Close(v8::Number::New(result));
102-
}
103-
case TYPE_INT:
104-
{
105-
jclass integerClazz = env->FindClass("java/lang/Integer");
106-
jmethodID integer_intValue = env->GetMethodID(integerClazz, "intValue", "()I");
107-
jint result = env->CallIntMethod(m_result, integer_intValue);
108-
return scope.Close(v8::Integer::New(result));
109-
}
110-
case TYPE_OBJECT:
111-
return scope.Close(JavaObject::New(m_java, m_result));
112-
case TYPE_STRING:
113-
return scope.Close(v8::String::New(javaObjectToString(env, m_result).c_str()));
114-
}
115-
return v8::Undefined();
79+
return scope.Close(javaToV8(m_java, env, m_resultType, m_result));
11680
}
11781

11882
void NewInstanceBaton::execute(JNIEnv *env) {

src/methodCallBaton.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class MethodCallBaton {
3333
jarray m_args;
3434
jobject m_result;
3535
jobject m_method;
36-
int m_resultType;
36+
jvalueType m_resultType;
3737
};
3838

3939
class InstanceMethodCallBaton : public MethodCallBaton {

src/utils.cpp

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <algorithm>
55
#include <sstream>
66
#include "javaObject.h"
7+
#include "java.h"
78

89
std::list<jobject> javaReflectionGetMethods(JNIEnv *env, jclass clazz) {
910
std::list<jobject> results;
@@ -73,7 +74,7 @@ jobject javaFindBestMatchingMethod(
7374
JNIEnv *env,
7475
std::list<jobject>& methods,
7576
const char *methodName,
76-
std::list<int>& argTypes) {
77+
std::list<jvalueType>& argTypes) {
7778

7879
std::list<jobject> possibleMatches;
7980
jclass methodClazz = env->FindClass("java/lang/reflect/Method");
@@ -112,7 +113,7 @@ jobject javaFindBestMatchingMethod(
112113
jobject javaFindBestMatchingConstructor(
113114
JNIEnv *env,
114115
std::list<jobject>& constructors,
115-
std::list<int>& argTypes) {
116+
std::list<jvalueType>& argTypes) {
116117

117118
std::list<jobject> possibleMatches;
118119
jclass constructorClazz = env->FindClass("java/lang/reflect/Constructor");
@@ -204,7 +205,7 @@ jobject javaFindField(JNIEnv* env, jclass clazz, std::string fieldName) {
204205
return NULL;
205206
}
206207

207-
jobject v8ToJava(JNIEnv* env, v8::Local<v8::Value> arg, int *methodArgType) {
208+
jobject v8ToJava(JNIEnv* env, v8::Local<v8::Value> arg, jvalueType *methodArgType) {
208209
if(arg->IsNull()) {
209210
return NULL;
210211
}
@@ -248,12 +249,12 @@ jobject v8ToJava(JNIEnv* env, v8::Local<v8::Value> arg, int *methodArgType) {
248249
return NULL;
249250
}
250251

251-
jarray v8ToJava(JNIEnv* env, const v8::Arguments& args, int start, int end, std::list<int> *methodArgTypes) {
252+
jarray v8ToJava(JNIEnv* env, const v8::Arguments& args, int start, int end, std::list<jvalueType> *methodArgTypes) {
252253
jclass clazz = env->FindClass("java/lang/Object");
253254
jobjectArray results = env->NewObjectArray(end-start, clazz, NULL);
254255

255256
for(int i=start; i<end; i++) {
256-
int methodArgType;
257+
jvalueType methodArgType;
257258
jobject val = v8ToJava(env, args[i], &methodArgType);
258259
env->SetObjectArrayElement(results, i - start, val);
259260
if(methodArgTypes) {
@@ -298,3 +299,45 @@ v8::Handle<v8::Value> javaExceptionToV8(JNIEnv* env, const std::string& alternat
298299
jthrowable ex = env->ExceptionOccurred();
299300
return scope.Close(javaExceptionToV8(env, ex, alternateMessage));
300301
}
302+
303+
v8::Handle<v8::Value> javaToV8(Java* java, JNIEnv* env, jvalueType resultType, jobject obj) {
304+
v8::HandleScope scope;
305+
306+
switch(resultType) {
307+
case TYPE_VOID:
308+
return v8::Undefined();
309+
case TYPE_BOOLEAN:
310+
{
311+
jclass booleanClazz = env->FindClass("java/lang/Boolean");
312+
jmethodID boolean_booleanValue = env->GetMethodID(booleanClazz, "booleanValue", "()Z");
313+
bool result = env->CallBooleanMethod(obj, boolean_booleanValue);
314+
return scope.Close(v8::Boolean::New(result));
315+
}
316+
case TYPE_BYTE:
317+
{
318+
jclass byteClazz = env->FindClass("java/lang/Byte");
319+
jmethodID byte_byteValue = env->GetMethodID(byteClazz, "byteValue", "()B");
320+
jbyte result = env->CallByteMethod(obj, byte_byteValue);
321+
return scope.Close(v8::Number::New(result));
322+
}
323+
case TYPE_LONG:
324+
{
325+
jclass longClazz = env->FindClass("java/lang/Long");
326+
jmethodID long_longValue = env->GetMethodID(longClazz, "longValue", "()J");
327+
jlong result = env->CallLongMethod(obj, long_longValue);
328+
return scope.Close(v8::Number::New(result));
329+
}
330+
case TYPE_INT:
331+
{
332+
jclass integerClazz = env->FindClass("java/lang/Integer");
333+
jmethodID integer_intValue = env->GetMethodID(integerClazz, "intValue", "()I");
334+
jint result = env->CallIntMethod(obj, integer_intValue);
335+
return scope.Close(v8::Integer::New(result));
336+
}
337+
case TYPE_OBJECT:
338+
return scope.Close(JavaObject::New(java, obj));
339+
case TYPE_STRING:
340+
return scope.Close(v8::String::New(javaObjectToString(env, obj).c_str()));
341+
}
342+
return v8::Undefined();
343+
}

src/utils.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <list>
88
#include <string>
99

10+
class Java;
11+
1012
typedef enum _jvalueType {
1113
TYPE_VOID = 1,
1214
TYPE_INT = 2,
@@ -26,19 +28,20 @@ jobject javaFindBestMatchingMethod(
2628
JNIEnv *env,
2729
std::list<jobject>& methods,
2830
const char *methodName,
29-
std::list<int>& argTypes);
31+
std::list<jvalueType>& argTypes);
3032
jobject javaFindBestMatchingConstructor(
3133
JNIEnv *env,
3234
std::list<jobject>& constructors,
33-
std::list<int>& argTypes);
35+
std::list<jvalueType>& argTypes);
3436
JNIEnv* javaAttachCurrentThread(JavaVM* jvm);
3537
void javaDetachCurrentThread(JavaVM* jvm);
3638
jvalueType javaGetType(JNIEnv *env, jclass type);
3739
jclass javaFindClass(JNIEnv* env, std::string className);
3840
jobject javaFindField(JNIEnv* env, jclass clazz, std::string fieldName);
39-
jarray v8ToJava(JNIEnv* env, const v8::Arguments& args, int start, int end, std::list<int> *methodArgTypes);
40-
jobject v8ToJava(JNIEnv* env, v8::Local<v8::Value> arg, int *methodArgType);
41+
jarray v8ToJava(JNIEnv* env, const v8::Arguments& args, int start, int end, std::list<jvalueType> *methodArgTypes);
42+
jobject v8ToJava(JNIEnv* env, v8::Local<v8::Value> arg, jvalueType *methodArgType);
4143
v8::Handle<v8::Value> javaExceptionToV8(JNIEnv* env, const std::string& alternateMessage);
4244
v8::Handle<v8::Value> javaExceptionToV8(JNIEnv* env, jthrowable ex, const std::string& alternateMessage);
45+
v8::Handle<v8::Value> javaToV8(Java* java, JNIEnv* env, jvalueType resultType, jobject obj);
4346

4447
#endif

test/Test.class

90 Bytes
Binary file not shown.

test/Test.java

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

22
public class Test {
3-
private int i;
3+
private int i;
4+
public static int staticFieldInt = 42;
45

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

test/java-staticField-test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
var java = require("./testHelpers").java;
3+
4+
var nodeunit = require("nodeunit");
5+
var util = require("util");
6+
7+
exports['Java - Static Field'] = nodeunit.testCase({
8+
"getStaticFieldValue int": function(test) {
9+
var val = java.getStaticFieldValue("Test", "staticFieldInt");
10+
test.equal(val, 42);
11+
test.done();
12+
},
13+
14+
"setStaticFieldValue int": function(test) {
15+
java.setStaticFieldValue("Test", "staticFieldInt", 112);
16+
var val = java.getStaticFieldValue("Test", "staticFieldInt");
17+
test.equal(val, 112);
18+
test.done();
19+
},
20+
});

0 commit comments

Comments
 (0)