1
1
#include " jni_utils.h"
2
+ #include < string>
2
3
3
- 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;
4
7
5
8
JNIEnv *getJNIEnv () {
6
9
JNIEnv *pEnv = NULL ;
@@ -20,6 +23,8 @@ JNIEnv *getJNIEnv() {
20
23
// Class fully qualified names
21
24
const char *CLS_NODE = " org/bblfsh/client/v2/Node" ;
22
25
const char *CLS_CTX = " org/bblfsh/client/v2/Context" ;
26
+ const char *CLS_OBJ = " java/lang/Object" ;
27
+ const char *CLS_RE = " java/lang/RuntimeException" ;
23
28
24
29
const char *CLS_JNODE = " org/bblfsh/client/v2/JNode" ;
25
30
const char *CLS_JNULL = " org/bblfsh/client/v2/JNull" ;
@@ -31,6 +36,7 @@ const char *CLS_JUINT = "org/bblfsh/client/v2/JUint";
31
36
const char *CLS_JARR = " org/bblfsh/client/v2/JArray" ;
32
37
const char *CLS_JOBJ = " org/bblfsh/client/v2/JObject" ;
33
38
39
+ // Method signatures
34
40
const char *METHOD_JNODE_KEY_AT = " (I)Ljava/lang/String;" ;
35
41
const char *METHOD_JNODE_VALUE_AT = " (I)Lorg/bblfsh/client/v2/JNode;" ;
36
42
const char *METHOD_JOBJ_ADD =
@@ -39,84 +45,105 @@ const char *METHOD_JOBJ_ADD =
39
45
const char *METHOD_JARR_ADD =
40
46
" (Lorg/bblfsh/client/v2/JNode;)Lscala/collection/mutable/Buffer;" ;
41
47
48
+ const char *METHOD_OBJ_TO_STR = " ()Ljava/lang/String;" ;
49
+
50
+ void checkJvmException (std::string msg) {
51
+ JNIEnv *env = getJNIEnv ();
52
+ if (env->ExceptionCheck ()) {
53
+ // env->ExceptionDescribe(); // prints to stdout, un-comment for debuging
54
+ auto err = env->ExceptionOccurred ();
55
+
56
+ jmethodID toString = env->GetMethodID (env->FindClass (CLS_OBJ), " toString" ,
57
+ METHOD_OBJ_TO_STR);
58
+ jstring s = (jstring)env->CallObjectMethod (err, toString);
59
+ const char *utf = env->GetStringUTFChars (s, 0 );
60
+ env->ReleaseStringUTFChars (s, utf);
61
+
62
+ env->ExceptionClear ();
63
+
64
+ auto exception = env->FindClass (CLS_RE);
65
+ env->ThrowNew (exception, msg.append (" : " ).append (utf).data ());
66
+ }
67
+ }
68
+
42
69
jobject NewJavaObject (JNIEnv *env, const char *className, const char *initSign,
43
70
...) {
44
71
jclass cls = env->FindClass (className);
45
- if (env->ExceptionOccurred () || !cls) {
46
- return nullptr ;
47
- }
72
+ checkJvmException (std::string (" failed to find a class " ).append (className));
48
73
49
74
jmethodID initId = env->GetMethodID (cls, " <init>" , initSign);
50
- if (env->ExceptionOccurred () || !initId) {
51
- return nullptr ;
52
- }
75
+ checkJvmException (
76
+ std::string (" failed to call <inti> constructor for " ).append (className));
53
77
54
78
va_list varargs;
55
79
va_start (varargs, initSign);
56
80
jobject instance = env->NewObjectV (cls, initId, varargs);
57
81
va_end (varargs);
58
- if (env->ExceptionOccurred () || !instance) {
59
- return nullptr ;
60
- }
82
+ checkJvmException (
83
+ std::string (" failed get varargs for constructor of " ).append (className));
61
84
62
85
return instance;
63
86
}
64
87
65
88
jfieldID getField (JNIEnv *env, jobject obj, const char *name) {
66
89
jclass cls = env->GetObjectClass (obj);
67
- if (env->ExceptionOccurred () || !cls) {
68
- return nullptr ;
69
- }
90
+ checkJvmException (" failed get an object class" );
70
91
71
92
jfieldID jfid = env->GetFieldID (cls, name, " J" );
72
- if (env->ExceptionOccurred () || !jfid) {
73
- return nullptr ;
74
- }
93
+ checkJvmException (std::string (" failed get a field " ).append (name));
94
+
75
95
return jfid;
76
96
}
77
97
78
98
static jmethodID MethodID (JNIEnv *env, const char *method,
79
99
const char *signature, const char *className) {
80
100
jclass cls = env->FindClass (className);
81
- if (env->ExceptionOccurred () || !cls) {
82
- return nullptr ;
83
- }
101
+ checkJvmException (std::string (" failed to find a class " ).append (className));
84
102
85
103
jmethodID mId = env->GetMethodID (cls, method, signature);
86
- if (env->ExceptionOccurred ()) {
87
- return nullptr ;
88
- }
104
+ checkJvmException (std::string (" failed get a method " )
105
+ .append (className)
106
+ .append (" ." )
107
+ .append (method));
89
108
90
109
return mId ;
91
110
}
92
111
93
112
jint IntMethod (JNIEnv *env, const char *method, const char *signature,
94
113
const char *className, const jobject *object) {
95
114
jmethodID mId = MethodID (env, method, signature, className);
96
- if (env->ExceptionOccurred () || !mId ) return 0 ;
97
- // TODO(bzz): add better error handling
98
- // ExceptionOccurred()
99
- // ExceptionDescribe()
100
- // ExceptionClear()
101
- // ExceptionCheck()
102
- // ThrowNew("failed to call $className.$method") to JVM
115
+ checkJvmException (std::string (" failed get a method " )
116
+ .append (className)
117
+ .append (" ." )
118
+ .append (method));
103
119
104
120
jint res = env->CallIntMethod (*object, mId );
105
- if (env->ExceptionOccurred ()) return 0 ;
121
+ checkJvmException (std::string (" failed call a method " )
122
+ .append (className)
123
+ .append (" ." )
124
+ .append (method)
125
+ .append (" using signature " )
126
+ .append (signature));
106
127
107
128
return res;
108
129
}
109
130
110
131
jobject ObjectMethod (JNIEnv *env, const char *method, const char *signature,
111
132
const char *className, const jobject *object, ...) {
112
133
jmethodID mId = MethodID (env, method, signature, className);
113
- if (env->ExceptionOccurred () || !mId ) return nullptr ;
134
+ checkJvmException (std::string (" failed get a method " )
135
+ .append (className)
136
+ .append (" ." )
137
+ .append (method));
114
138
115
139
va_list varargs;
116
140
va_start (varargs, object);
117
141
jobject res = env->CallObjectMethodV (*object, mId , varargs);
118
142
va_end (varargs);
119
- if (env->ExceptionOccurred () || !res) return nullptr ;
143
+ checkJvmException (std::string (" failed get varargs for " )
144
+ .append (className)
145
+ .append (" ." )
146
+ .append (method));
120
147
121
148
return res;
122
149
}
0 commit comments