@@ -50,6 +50,13 @@ const char METHOD_JARR_ADD[] =
50
50
51
51
const char METHOD_OBJ_TO_STR[] = " ()Ljava/lang/String;" ;
52
52
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
+
53
60
// TODO(bzz): cache classes&methods in JNI_OnLoad should speed this up
54
61
void checkJvmException (std::string msg) {
55
62
JNIEnv *env = getJNIEnv ();
@@ -58,23 +65,15 @@ void checkJvmException(std::string msg) {
58
65
env->ExceptionClear ();
59
66
60
67
auto exceptionCls = env->FindClass (CLS_RE);
61
- if (env->ExceptionCheck ()) {
68
+ if (env->ExceptionCheck () || !exceptionCls ) {
62
69
env->ExceptionClear ();
63
70
env->Throw (env->ExceptionOccurred ());
64
71
return ;
65
72
}
66
73
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) {
78
77
env->ExceptionClear ();
79
78
env->ThrowNew (exceptionCls,
80
79
msg.append (" - failed to find method toString" ).data ());
@@ -83,19 +82,39 @@ void checkJvmException(std::string msg) {
83
82
84
83
jstring s = (jstring)env->CallObjectMethod (err, toString);
85
84
if (env->ExceptionCheck () || !s) {
85
+ env->ExceptionClear ();
86
86
env->ThrowNew (exceptionCls,
87
87
msg.append (" - failed co call method toString" ).data ());
88
88
return ;
89
89
}
90
90
91
91
const char *utf = env->GetStringUTFChars (s, 0 );
92
+ jstring jmsg = env->NewStringUTF (msg.append (" : " ).append (utf).c_str ());
92
93
env->ReleaseStringUTFChars (s, utf);
93
94
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
+ }
99
118
100
119
env->Throw (exception );
101
120
}
@@ -122,14 +141,67 @@ jobject NewJavaObject(JNIEnv *env, const char *className, const char *initSign,
122
141
return instance;
123
142
}
124
143
125
- jfieldID getField (JNIEnv *env, jobject obj, const char *name) {
144
+ jfieldID FieldID (JNIEnv *env, jobject obj, const char *field,
145
+ const char *typeSignature) {
126
146
jclass cls = env->GetObjectClass (obj);
127
147
checkJvmException (" failed get the class of an object" );
128
148
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
+ }
131
184
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;
133
205
}
134
206
135
207
jmethodID MethodID (JNIEnv *env, const char *method, const char *signature,
@@ -184,3 +256,10 @@ jobject ObjectMethod(JNIEnv *env, const char *method, const char *signature,
184
256
185
257
return res;
186
258
}
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
+ }
0 commit comments