Mục lục
Khi làm việc với Java Reflection, việc xảy ra lỗi InvocationTargetException là rất thường xuyên. Trong bài viết này chúng ta sẽ cùng nhau tìm hiểu nguyên nhân làm xảy ra exception này và cách để xử lý nó.
Nguyên nhân xảy ra lỗi InvocationTargetException
Lỗi này chủ yếu xảy ra khi chúng ta sử dụng Java Reflection để gọi một method hoặc một constructor mà bản thân chúng đã ném ra một exception.
Giả sử chúng ta có một hàm khi gọi đến thì nó xảy ra exception như sau
public class InvocationTargetExample { public int divideByZeroExample() { return 1 / 0; } }
Bây giờ chúng ta sẽ kiểm thử với Junit 5
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.junit.jupiter.api.Test; public class InvocationTargetUnitTest { @Test public void whenCallingMethodThrowsException_thenAssertCauseOfInvocationTargetException() throws Exception { InvocationTargetExample targetExample = new InvocationTargetExample(); Method method = InvocationTargetExample.class.getMethod("divideByZeroExample"); Exception exception = assertThrows(InvocationTargetException.class, () -> method.invoke(targetExample)); } }
Trong đoạn code phía treenm chúng ta có thể thấy rằng việc dùng Reflection để gọi đến divideByZeroExample() method sẽ gây ra InvocationTargetException. Một điểm quan trọng chúng ta cần chú ý ở đây là divideByZeroExample() thật chất sẽ throw ra ArithmeticException thế nhưng thông qua reflection chúng ta lại nhận được InvocationTargetException.
Chúng ta sẽ đặt ra câu hỏi là tại sao reflection lại không trả về exception gốc là ArithmeticException thay vì InvocationTargetException. Chúng ta cần phải hiểu là bản thân reflection là một tầng bao bọc phía bên ngoài, bất kỳ một exception nào xảy ra đều đã đi qua bộ xử lý exception của nó trước. Do đó ArithmeticException đã được reflection dịch sangInvocationTargetException.
Cách giải quyết InvocationTargetException
Mặc dù chúng ta nhận được InvocationTargetException, nhưng chúng ta có thể gọiThrowable.getCause() để biết thêm nhiều thông tin hơn.
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.junit.jupiter.api.Test; public class InvocationTargetUnitTest { @Test public void whenCallingMethodThrowsException_thenAssertCauseOfInvocationTargetException() throws Exception { InvocationTargetExample targetExample = new InvocationTargetExample(); Method method = InvocationTargetExample.class.getMethod("divideByZeroExample"); Exception exception = assertThrows(InvocationTargetException.class, () -> method.invoke(targetExample)); assertEquals(ArithmeticException.class, exception.getCause().getClass()); } }
Chúng ta có thể thấy sử dụng getCause() đã trả về đúng như Exception ban đầu, khi các bạn biết được đúng exception nào đang xảy ra thì có thể tìm ra cách để xử lý đúng cách chẳng hạn như ghi log, trả về dữ liệu mặc định trong trường hợp xảy ra exception v.v
Tóm lược
Qua bài viết này chúng ta đã tìm hiểu được một exception thường xuyên xảy ra trong Java Reflection. Do exception này thường có thông tin rất chung nên khó để chúng ta giải quyết, do đó việc sử dụng getCaused() sẽ cho chúng ta biết được chính xác exception nào đang thật sự xảy ra.
Nguồn: Baeldung