1
1
#include " jni_utils.h"
2
+ #include < string>
2
3
3
- // Class fully qualified names
4
- const char *CLS_NODE = " org/bblfsh/client/v2/Node" ;
5
- const char *CLS_CTX = " org/bblfsh/client/v2/Context" ;
6
-
7
- extern JavaVM *jvm; // FIXME(bzz): double-check and document
4
+ // TODO(bzz): double-check and document. Suggestion and more context at
5
+ // https://github.com/bblfsh/client-scala/pull/84#discussion_r288347756
6
+ extern JavaVM *jvm;
8
7
9
8
JNIEnv *getJNIEnv () {
10
9
JNIEnv *pEnv = NULL ;
@@ -21,38 +20,161 @@ JNIEnv *getJNIEnv() {
21
20
return pEnv;
22
21
}
23
22
23
+ const char CLS_NODE[] = " org/bblfsh/client/v2/Node" ;
24
+ const char CLS_CTX[] = " org/bblfsh/client/v2/Context" ;
25
+ const char CLS_OBJ[] = " java/lang/Object" ;
26
+ const char CLS_RE[] = " java/lang/RuntimeException" ;
27
+ const char CLS_JNODE[] = " org/bblfsh/client/v2/JNode" ;
28
+ const char CLS_JNULL[] = " org/bblfsh/client/v2/JNull" ;
29
+ const char CLS_JSTR[] = " org/bblfsh/client/v2/JString" ;
30
+ const char CLS_JINT[] = " org/bblfsh/client/v2/JInt" ;
31
+ const char CLS_JFLT[] = " org/bblfsh/client/v2/JFloat" ;
32
+ const char CLS_JBOOL[] = " org/bblfsh/client/v2/JBool" ;
33
+ const char CLS_JUINT[] = " org/bblfsh/client/v2/JUint" ;
34
+ const char CLS_JARR[] = " org/bblfsh/client/v2/JArray" ;
35
+ const char CLS_JOBJ[] = " org/bblfsh/client/v2/JObject" ;
36
+
37
+ const char METHOD_JNODE_KEY_AT[] = " (I)Ljava/lang/String;" ;
38
+ const char METHOD_JNODE_VALUE_AT[] = " (I)Lorg/bblfsh/client/v2/JNode;" ;
39
+ const char METHOD_JOBJ_ADD[] =
40
+ " (Ljava/lang/String;Lorg/bblfsh/client/v2/JNode;)Lscala/collection/"
41
+ " mutable/Buffer;" ;
42
+ const char METHOD_JARR_ADD[] =
43
+ " (Lorg/bblfsh/client/v2/JNode;)Lscala/collection/mutable/Buffer;" ;
44
+
45
+ const char METHOD_OBJ_TO_STR[] = " ()Ljava/lang/String;" ;
46
+
47
+ // TODO(bzz): cache classes&methods in JNI_OnLoad should speed this up
48
+ void checkJvmException (std::string msg) {
49
+ JNIEnv *env = getJNIEnv ();
50
+ auto err = env->ExceptionOccurred ();
51
+ if (err) {
52
+ env->ExceptionClear ();
53
+
54
+ auto exceptionCls = env->FindClass (CLS_RE);
55
+ if (env->ExceptionCheck ()) {
56
+ env->ExceptionClear ();
57
+ env->Throw (env->ExceptionOccurred ());
58
+ return ;
59
+ }
60
+
61
+ jclass cls = env->FindClass (CLS_OBJ);
62
+ if (env->ExceptionCheck ()) {
63
+ env->ExceptionClear ();
64
+ env->ThrowNew (
65
+ exceptionCls,
66
+ msg.append (" - failed to find class " ).append (CLS_OBJ).data ());
67
+ return ;
68
+ }
69
+
70
+ jmethodID toString = env->GetMethodID (cls, " toString" , METHOD_OBJ_TO_STR);
71
+ if (env->ExceptionCheck ()) {
72
+ env->ExceptionClear ();
73
+ env->ThrowNew (exceptionCls,
74
+ msg.append (" - failed to find method toString" ).data ());
75
+ return ;
76
+ }
77
+
78
+ jstring s = (jstring)env->CallObjectMethod (err, toString);
79
+ if (env->ExceptionCheck () || !s) {
80
+ env->ThrowNew (exceptionCls,
81
+ msg.append (" - failed co call method toString" ).data ());
82
+ return ;
83
+ }
84
+
85
+ const char *utf = env->GetStringUTFChars (s, 0 );
86
+ env->ReleaseStringUTFChars (s, utf);
87
+
88
+ // new RuntimeException(msg.data(), err)
89
+ jmethodID initId = env->GetMethodID (
90
+ cls, " <init>" , " (Ljava/lang/String;Ljava/lang/Throwable;)V" );
91
+ jthrowable exception = (jthrowable)env->NewObject (
92
+ exceptionCls, initId, msg.append (" : " ).append (utf).data (), err);
93
+
94
+ env->Throw (exception );
95
+ }
96
+ }
97
+
24
98
jobject NewJavaObject (JNIEnv *env, const char *className, const char *initSign,
25
99
...) {
26
100
jclass cls = env->FindClass (className);
27
- if (env->ExceptionOccurred () || !cls) {
28
- return NULL ;
29
- }
101
+ checkJvmException (std::string (" failed to find a class " ).append (className));
30
102
31
103
jmethodID initId = env->GetMethodID (cls, " <init>" , initSign);
32
- if (env->ExceptionOccurred () || !initId) {
33
- return NULL ;
34
- }
104
+ checkJvmException (std::string (" failed to call a constructor with signature " )
105
+ .append (initSign)
106
+ .append (" for the class name " )
107
+ .append (className));
35
108
36
109
va_list varargs;
37
110
va_start (varargs, initSign);
38
111
jobject instance = env->NewObjectV (cls, initId, varargs);
39
112
va_end (varargs);
40
- if (env->ExceptionOccurred () || !instance) {
41
- return NULL ;
42
- }
113
+ checkJvmException (
114
+ std::string (" failed get varargs for constructor of " ).append (className));
43
115
44
116
return instance;
45
117
}
46
118
47
119
jfieldID getField (JNIEnv *env, jobject obj, const char *name) {
48
120
jclass cls = env->GetObjectClass (obj);
49
- if (env->ExceptionOccurred () || !cls) {
50
- return nullptr ;
51
- }
121
+ checkJvmException (" failed get the class of an object" );
52
122
53
123
jfieldID jfid = env->GetFieldID (cls, name, " J" );
54
- if (env->ExceptionOccurred () || !jfid) {
55
- return nullptr ;
56
- }
124
+ checkJvmException (std::string (" failed get a field " ).append (name));
125
+
57
126
return jfid;
58
127
}
128
+
129
+ static jmethodID MethodID (JNIEnv *env, const char *method,
130
+ const char *signature, const char *className) {
131
+ jclass cls = env->FindClass (className);
132
+ checkJvmException (std::string (" failed to find a class " ).append (className));
133
+
134
+ jmethodID mId = env->GetMethodID (cls, method, signature);
135
+ checkJvmException (std::string (" failed to get method " )
136
+ .append (className)
137
+ .append (" ." )
138
+ .append (method));
139
+
140
+ return mId ;
141
+ }
142
+
143
+ jint IntMethod (JNIEnv *env, const char *method, const char *signature,
144
+ const char *className, const jobject *object) {
145
+ jmethodID mId = MethodID (env, method, signature, className);
146
+ checkJvmException (std::string (" failed to get method " )
147
+ .append (className)
148
+ .append (" ." )
149
+ .append (method));
150
+
151
+ jint res = env->CallIntMethod (*object, mId );
152
+ checkJvmException (std::string (" failed to call method " )
153
+ .append (className)
154
+ .append (" ." )
155
+ .append (method)
156
+ .append (" using signature " )
157
+ .append (signature));
158
+
159
+ return res;
160
+ }
161
+
162
+ jobject ObjectMethod (JNIEnv *env, const char *method, const char *signature,
163
+ const char *className, const jobject *object, ...) {
164
+ jmethodID mId = MethodID (env, method, signature, className);
165
+ checkJvmException (std::string (" failed to get method " )
166
+ .append (className)
167
+ .append (" ." )
168
+ .append (method));
169
+
170
+ va_list varargs;
171
+ va_start (varargs, object);
172
+ jobject res = env->CallObjectMethodV (*object, mId , varargs);
173
+ va_end (varargs);
174
+ checkJvmException (std::string (" failed get varargs for " )
175
+ .append (className)
176
+ .append (" ." )
177
+ .append (method));
178
+
179
+ return res;
180
+ }
0 commit comments