JNI – Exception


Được đăng vào ngày 04/01/2017 | 0 bình luận
JNI – Exception
Đánh giá bài viết

Trong phần này chúng ta sẽ tìm hiểu cách bắt lỗi Exception và giải phóng lỗi Exception từ code native.

Nếu bạn chưa biết thì Exception là lỗi xảy ra trong quá trình chạy, ví dụ đơn giản nhất là phép chia cho 0, trong Java khi gặp câu lệnh chia cho 0 thì JVM sẽ báo lỗi ArithmeticException.

Bắt lỗi Exception

Đầu tiên chúng ta có đoạn code Java như sau:

class TryCatch {
    static { System.loadLibrary("TryCatch"); }
 
    private native void catchError();
    private void division(int a, int b) throws ArithmeticException{ 
        int result = a / b; 
        System.out.println(a + " / " + b + " = " + result);
    }
 
    public static void main(String[] args) { 
        new TryCatch().catchError(); 
    }
}

Chúng ta có một phương thức native là CatchError() và một phương thức thường là division(), phương thức division() sẽ nhận vào 2 số nguyên, thực hiện phép chia 2 số nguyên này và sẽ giải phóng lỗi ArithmeticException nếu có.

Như bình thường thì chúng ta sẽ bọc đoạn code thực hiện phép chia đó trong try...catch, nhưng ở đây chúng ta không làm thế mà chúng ta sẽ xử lý lỗi này trong phần code native.

Chúng ta bắt lỗi trong native như sau:

#include "TryCatch.h"
#include <iostream>
using namespace std;

JNIEXPORT void JNICALL Java_TryCatch_catchError (JNIEnv *e, jobject obj) {    
    jclass cls = e->GetObjectClass(obj);
    jmethodID mid = e->GetMethodID(cls, "division", "(II)V");
    e->CallVoidMethod(obj, mid, 3, 0);
 
    jthrowable exc = e->ExceptionOccurred();
 
    if(exc != NULL) {
        cout << "Exception occurred:" << endl;
        e->ExceptionDescribe(); 
        e->ExceptionClear();
    }
}

Đầu tiên chúng ta lấy jclass, rồi lấy jmethodID của phương thức division() bên Java, sau đó chúng ta gọi phương thức đó với tham số 3 và 0, tức là làm phép chia 3 / 0.

Phương thức division() bên Java sẽ giải phóng lỗi ArithmeticException, ở C++ để kiểm tra xem có lỗi xảy ra không thì chúng ta gọi phương thức ExceptionOccured(), nếu có lỗi xảy ra thì phương thức này sẽ trả về một đối tượng jthrowable, chúng ta kiểm tra xem đối tượng này có NULL không, nếu có thì chúng ta in câu thông báo, sau đó gọi phương thức ExceptionDescribe(), phương thức này sẽ in stacktrace của lỗi, cuối cùng chúng ta gọi phương thức ExceptionClear() để xóa lỗi đó trong JVM.

Thực ra thì nếu không gọi ExceptionDescribe() thì JVM cũng sẽ tự động in đoạn stacktrace ra, nhưng sau đó JVM cũng sẽ dừng chương trình luôn, nếu chúng ta có gọi ExceptionDescribe() thì sau khi in stacktrace ra thì chương trình vẫn chạy cho đến khi kết thúc.

Exception occurred:
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at TryCatch.division(TryCatch.java:10)
    at TryCatch.catchError(Native Method)
    at TryCatch.main(TryCatch.java:18)

Giải phóng lỗi Exception

Để giải phóng lỗi Exception từ code C++ thì cũng khá đơn giản.

Chúng ta có code Java như sau:

class TryCatch {
    static { System.loadLibrary("TryCatch"); }
 
    private native void makeError();
 
    public static void main(String[] args) { 
        try {
            new TryCatch().makeError();
         } catch(Exception e) {
             System.out.println("Something happened:");
             e.printStackTrace();
         }
    }
}

Chúng ta có phương thức native là makeError(), phương thức này sẽ giải phóng lỗi Exception.

Chúng ta làm việc đó như sau:

#include "TryCatch.h"

JNIEXPORT void JNICALL Java_TryCatch_makeError (JNIEnv *e, jobject obj) {
    jclass exceptionCls = e->FindClass("java/lang/Exception");
    e->ThrowNew(exceptionCls, "thrown from C++ code");
}

Đầu tiên chúng ta tìm một lớp Exception bên Java mà chúng ta muốn tạo, ở đây mình dùng lớp java.lang.Exception, rồi dùng phương thức FindClass() để lấy đối tượng jclass.

Sau đó để giải phóng lỗi này thì chỉ cần gọi phương thức ThrowNew() là được, phương thức này nhận vào đối tượng jclass và một đoạn chuỗi mô tả lỗi.

Something happened:
java.lang.Exception: thrown from C++ code
    at TryCatch.makeError(Native Method)
    at TryCatch.main(TryCatch.java:8)






Bình luận

Hãy trở thành người đầu tiên bình luận

Thông báo cho tôi qua email khi
avatar
wpDiscuz