Skip to content
This repository was archived by the owner on Mar 8, 2020. It is now read-only.

Commit ee89f22

Browse files
authored
Merge pull request #106 from bzz/iterator
Iterator implementation
2 parents fabffdd + d16d3cd commit ee89f22

15 files changed

+697
-119
lines changed

src/main/native/jni_utils.cc

+100-21
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ const char METHOD_JARR_ADD[] =
5050

5151
const char METHOD_OBJ_TO_STR[] = "()Ljava/lang/String;";
5252

53+
const char METHOD_RE_INIT[] = "(Ljava/lang/String;)V";
54+
const char METHOD_RE_INIT_CAUSE[] =
55+
"(Ljava/lang/String;Ljava/lang/Throwable;)V";
56+
57+
// Field signatures
58+
const char FIELD_ITER_NODE[] = "Ljava/lang/Object;";
59+
5360
// TODO(bzz): cache classes&methods in JNI_OnLoad should speed this up
5461
void checkJvmException(std::string msg) {
5562
JNIEnv *env = getJNIEnv();
@@ -58,23 +65,15 @@ void checkJvmException(std::string msg) {
5865
env->ExceptionClear();
5966

6067
auto exceptionCls = env->FindClass(CLS_RE);
61-
if (env->ExceptionCheck()) {
68+
if (env->ExceptionCheck() || !exceptionCls) {
6269
env->ExceptionClear();
6370
env->Throw(env->ExceptionOccurred());
6471
return;
6572
}
6673

67-
jclass cls = env->FindClass(CLS_OBJ);
68-
if (env->ExceptionCheck()) {
69-
env->ExceptionClear();
70-
env->ThrowNew(
71-
exceptionCls,
72-
msg.append(" - failed to find class ").append(CLS_OBJ).data());
73-
return;
74-
}
75-
76-
jmethodID toString = env->GetMethodID(cls, "toString", METHOD_OBJ_TO_STR);
77-
if (env->ExceptionCheck()) {
74+
jmethodID toString =
75+
env->GetMethodID(exceptionCls, "toString", METHOD_OBJ_TO_STR);
76+
if (env->ExceptionCheck() || !toString) {
7877
env->ExceptionClear();
7978
env->ThrowNew(exceptionCls,
8079
msg.append(" - failed to find method toString").data());
@@ -83,19 +82,39 @@ void checkJvmException(std::string msg) {
8382

8483
jstring s = (jstring)env->CallObjectMethod(err, toString);
8584
if (env->ExceptionCheck() || !s) {
85+
env->ExceptionClear();
8686
env->ThrowNew(exceptionCls,
8787
msg.append(" - failed co call method toString").data());
8888
return;
8989
}
9090

9191
const char *utf = env->GetStringUTFChars(s, 0);
92+
jstring jmsg = env->NewStringUTF(msg.append(": ").append(utf).c_str());
9293
env->ReleaseStringUTFChars(s, utf);
9394

94-
// new RuntimeException(msg.data(), err)
95-
jmethodID initId = env->GetMethodID(
96-
cls, "<init>", "(Ljava/lang/String;Ljava/lang/Throwable;)V");
97-
jthrowable exception = (jthrowable)env->NewObject(
98-
exceptionCls, initId, msg.append(": ").append(utf).data(), err);
95+
// new RuntimeException(jmsg, err)
96+
jmethodID initId =
97+
env->GetMethodID(exceptionCls, "<init>", METHOD_RE_INIT_CAUSE);
98+
if (env->ExceptionCheck() || !initId) {
99+
env->ExceptionClear();
100+
env->ThrowNew(exceptionCls,
101+
msg.append(" - failed to get method id for signature ")
102+
.append(METHOD_RE_INIT_CAUSE)
103+
.c_str());
104+
return;
105+
}
106+
107+
jthrowable exception =
108+
(jthrowable)env->NewObject(exceptionCls, initId, jmsg, err);
109+
if (env->ExceptionCheck() || !exception) {
110+
env->ExceptionClear();
111+
env->ThrowNew(exceptionCls,
112+
msg.append(" - failed to create a new instance of ")
113+
.append(CLS_RE)
114+
.append(METHOD_RE_INIT_CAUSE)
115+
.c_str());
116+
return;
117+
}
99118

100119
env->Throw(exception);
101120
}
@@ -122,14 +141,67 @@ jobject NewJavaObject(JNIEnv *env, const char *className, const char *initSign,
122141
return instance;
123142
}
124143

125-
jfieldID getField(JNIEnv *env, jobject obj, const char *name) {
144+
jfieldID FieldID(JNIEnv *env, jobject obj, const char *field,
145+
const char *typeSignature) {
126146
jclass cls = env->GetObjectClass(obj);
127147
checkJvmException("failed get the class of an object");
128148

129-
jfieldID jfid = env->GetFieldID(cls, name, "J");
130-
checkJvmException(std::string("failed get a field ").append(name));
149+
// Note: printing the type from Scala to find the type needed for GetFieldID
150+
// third argument using getClass.getName sometimes return objects different
151+
// from the ones needed for the signature. To find the right type to use do
152+
// this from Scala: (instance).getClass.getDeclaredField("fieldName")
153+
jfieldID fId = env->GetFieldID(cls, field, typeSignature);
154+
checkJvmException(std::string("failed get a field ID '")
155+
.append(field)
156+
.append("' for type signature '")
157+
.append(typeSignature)
158+
.append("'"));
159+
160+
return fId;
161+
}
162+
jobject ObjectField(JNIEnv *env, jobject obj, const char *name,
163+
const char *signature) {
164+
jfieldID fId = FieldID(env, obj, name, signature);
165+
if (!fId) {
166+
jstring jmsg =
167+
env->NewStringUTF(std::string("failed to get field ID for field name '")
168+
.append(name)
169+
.append("' with signature '")
170+
.append(signature)
171+
.append("'")
172+
.c_str());
173+
jthrowable re =
174+
(jthrowable)NewJavaObject(env, CLS_RE, METHOD_RE_INIT, jmsg);
175+
env->Throw(re);
176+
return nullptr;
177+
}
178+
jobject fld = env->GetObjectField(obj, fId);
179+
checkJvmException(std::string("failed get an object from field '")
180+
.append(name)
181+
.append("'"));
182+
return fld;
183+
}
131184

132-
return jfid;
185+
jint IntField(JNIEnv *env, jobject obj, const char *name,
186+
const char *signature) {
187+
jfieldID fId = FieldID(env, obj, name, signature);
188+
if (!fId) {
189+
jstring jmsg =
190+
env->NewStringUTF(std::string("failed to get field ID for field name '")
191+
.append(name)
192+
.append("' with signature '")
193+
.append(signature)
194+
.append("'")
195+
.c_str());
196+
jthrowable re =
197+
(jthrowable)NewJavaObject(env, CLS_RE, METHOD_RE_INIT, jmsg);
198+
env->Throw(re);
199+
return -1;
200+
}
201+
jint fld = env->GetIntField(obj, fId);
202+
checkJvmException(
203+
std::string("failed get an Int from field '").append(name).append("'"));
204+
return fld;
133205
}
134206

135207
jmethodID MethodID(JNIEnv *env, const char *method, const char *signature,
@@ -184,3 +256,10 @@ jobject ObjectMethod(JNIEnv *env, const char *method, const char *signature,
184256

185257
return res;
186258
}
259+
260+
void ThrowByName(JNIEnv *env, const char *className, const char *msg) {
261+
jclass cls = env->FindClass(className);
262+
if (cls) {
263+
env->ThrowNew(cls, msg);
264+
}
265+
}

src/main/native/jni_utils.h

+39-5
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,56 @@ extern const char METHOD_JNODE_VALUE_AT[];
2727
extern const char METHOD_JOBJ_ADD[];
2828
extern const char METHOD_JARR_ADD[];
2929
extern const char METHOD_OBJ_TO_STR[];
30+
extern const char METHOD_RE_INIT[];
31+
extern const char METHOD_RE_INIT_CAUSE[];
3032

31-
// Checks though JNI, if there is a pending excption on JVM side.
33+
// Field signatures
34+
extern const char FIELD_ITER_NODE[];
35+
36+
// Checks through JNI, if there is a pending excption on the JVM side.
3237
//
33-
// Throws new RuntimeExpection to JVM in case there is,
34-
// uses the origial one as a cause and the given string as a message.
38+
// Throws new RuntimeException to the JVM in case there is,
39+
// uses the original one as a cause and the given string as a message.
3540
void checkJvmException(std::string);
3641

42+
// Reads the JVM pointer of the current native thread.
43+
//
44+
// If the thread was not created by JVM - it will be attached to the JVM first.
45+
// Those threads need to be detached later on, in order to avoid memory leaks.
3746
JNIEnv *getJNIEnv();
47+
48+
// Constructs new Java object of a given className and constructor signature.
3849
jobject NewJavaObject(JNIEnv *, const char *, const char *, ...);
39-
jfieldID getField(JNIEnv *env, jobject obj, const char *name);
4050

51+
// Returns the field ID of the field of the given object.
52+
// The field is specified by its name and signature.
53+
jfieldID FieldID(JNIEnv *, jobject, const char *, const char *);
54+
55+
// Reads the value of an Int field of a given object.
56+
// The field is specified by its name and signature.
57+
jint IntField(JNIEnv *, jobject, const char *, const char *);
58+
59+
// Reads the value of an Object field of a given object.
60+
// The field is specified by its name and signature.
61+
jobject ObjectField(JNIEnv *, jobject, const char *, const char *);
62+
63+
// Returns the method ID for a method of a given class or interface name.
64+
// The method is determined by its name and signature.
65+
jmethodID MethodID(JNIEnv *, const char *, const char *, const char *);
66+
67+
// Calls a method of the given class or interface name that returns an Int.
68+
// The method is determined by its name and signature.
4169
jint IntMethod(JNIEnv *, const char *, const char *, const char *,
4270
const jobject *);
4371

72+
// Calls a method of the given class or interface name that returns an Object.
73+
// The method is determined by its name and signature.
4474
jobject ObjectMethod(JNIEnv *, const char *, const char *, const char *,
4575
const jobject *, ...);
4676

47-
jmethodID MethodID(JNIEnv *, const char *, const char *, const char *);
77+
// Constructs new object the given class name and throws it to JVM.
78+
//
79+
// A fully qualified class name must name a valid Throwable type.
80+
// It does not interfere with the native control flow.
81+
void ThrowByName(JNIEnv *, const char *, const char *);
4882
#endif

0 commit comments

Comments
 (0)