Apa yang bisa menyebabkan java.lang.reflect.InvocationTargetException?

313

Yah, saya sudah mencoba memahami dan membaca apa yang menyebabkannya, tetapi saya tidak bisa mendapatkannya:

Saya punya ini di suatu tempat dalam kode saya:

 try{
 ..
 m.invoke(testObject);
 ..
 } catch(AssertionError e){
 ...
 } catch(Exception e){
 ..
 }

Masalahnya adalah, ketika ia mencoba untuk memanggil beberapa metode itu melempar InvocationTargetExceptionbukannya beberapa pengecualian yang diharapkan lainnya (khusus ArrayIndexOutOfBoundsException). Ketika saya benar-benar tahu metode apa yang dipanggil saya langsung ke kode metode ini dan menambahkan blok try-catch untuk garis yang ArrayIndexOutOfBoundsExceptionseharusnya melempar dan itu benar-benar melempar ArrayIndexOutOfBoundsExceptionseperti yang diharapkan. Namun ketika naik itu entah bagaimana berubah menjadi InvocationTargetExceptiondan dalam kode di atas catch(Exception e) e adalah InvocationTargetExceptiondan tidak ArrayIndexOutOfBoundsException seperti yang diharapkan.

Apa yang bisa menyebabkan perilaku seperti itu atau bagaimana saya bisa memeriksa hal seperti itu?

pengguna550413
sumber

Jawaban:

333

Anda telah menambahkan tingkat abstraksi ekstra dengan memanggil metode dengan refleksi. Lapisan refleksi membungkus setiap pengecualian dalam InvocationTargetException, yang memungkinkan Anda memberi tahu perbedaan antara pengecualian yang sebenarnya disebabkan oleh kegagalan dalam panggilan refleksi (misalnya, daftar argumen Anda tidak valid) dan kegagalan dalam metode yang disebut.

Buka saja penyebabnya di dalam InvocationTargetExceptiondan Anda akan mendapatkan yang asli.

Jon Skeet
sumber
4
@ user550413: Dengan membuka bungkus pengecualian dan memeriksanya, tentu saja. Anda selalu bisa melemparnya sendiri, dan menangkapnya seperti itu jika harus.
Jon Skeet
157
Bagi siapa pun yang bertanya-tanya tentang apa artinya "membuka penyebab dalam InvocationTargetException", saya baru saja menemukan bahwa jika Anda mendapatkannya dicetak menggunakan exception.printStackTrace(), Anda hanya melihat bagian "Disebabkan Oleh:" bukannya bagian atas / bagian normal.
Jan
31
Untuk menambahkan penjelasan tentang "membuka" Anda juga dapat menangkap pengecualian dan menggunakan metode getCause () di atasnya, yang juga dapat diposisikan ulang, jika diinginkan. Sesuatu seperti try {...} catch (InvocationTargetException ex) { log.error("oops!", ex.getCause()) }atau...catch... { throw ex.getCause() }
jcadcell
4
+1 @HJanrs for you just look at the "Caused By:" section instead of the top half/normal section
GingerHead
1
@DheraajBhaskar Jangan mengedit jawaban orang lain seolah-olah itu jawaban Anda sendiri, dan jangan gunakan format kutipan untuk teks yang tidak dikutip. Hasil edit itu seharusnya sudah diposting sebagai komentar.
Marquis of Lorne
51

Pengecualian dilemparkan jika

InvocationTargetException - jika metode yang mendasarinya melempar pengecualian.

Jadi jika metode, yang telah dipanggil dengan API refleksi, melempar pengecualian (pengecualian runtime misalnya), API refleksi akan membungkus pengecualian menjadi InvocationTargetException.

Andreas Dolk
sumber
penjelasan yang bagus!
gaurav
Bagaimana jika saya mengharapkan metode yang mendasari untuk melemparkan pengecualian? Haruskah saya menangkap pengecualian ini dan hanya memikirkan kembali?
jDub9
46

Gunakan getCause()metode pada InvocationTargetExceptionuntuk mengambil pengecualian asli.

Daniel Ward
sumber
21

Dari Javadoc of Method.invoke ()

Melempar: InvocationTargetException - jika metode yang mendasarinya melempar pengecualian.

Pengecualian ini dilemparkan jika metode yang disebut melemparkan pengecualian.

Peter Lawrey
sumber
Jadi bayangkan saya memiliki kaskade java.lang.reflect.Proxycontoh yang menambah objek terbungkus. Setiap Proxyanggun menangani pengecualian tertentu (mungkin dilemparkan oleh objek yang dibungkus) dengan menggunakan miliknya sendiri InvocationHandler. Untuk pengecualian yang beriak melalui kaskade ini hingga mencapai penangan / proxy pemanggilan yang benar, di masing-masing InvocationHandler, saya akan menangkap InvocationTargetException, membuka bungkusannya, memeriksa apakah pengecualian yang dibungkus adalah instanceofpengecualian untuk ditangani oleh ini InvocationHandler. Jika itu bukan instanceof, saya akan melemparkan pengecualian yang terbuka ... benar?
Abdull
Saya akan selalu melemparkan pengecualian yang terbuka.
Peter Lawrey
9

Itu InvocationTargetExceptionmungkin membungkus Anda ArrayIndexOutOfBoundsException. Tidak ada yang bisa mengatakan di muka ketika menggunakan refleksi apa metode itu bisa melempar - jadi daripada menggunakan throws Exceptionpendekatan, semua pengecualian ditangkap dan dimasukkan ke dalam InvocationTargetException.

Liv
sumber
Terima kasih, tetapi bagaimana saya akan membedakan antara (AssertionError e) dan (Exception e) misalnya? Jika saya selalu mendapatkan InvocationTargetException terlebih dahulu sebelum membuka bungkus penyebabnya, di mana saya akan berbeda di antara setiap pengecualian?
user550413
9

Ini akan mencetak baris kode yang tepat dalam metode tertentu, yang ketika dipanggil, menimbulkan pengecualian:

try {

    // try code
    ..
    m.invoke(testObject);
    ..

} catch (InvocationTargetException e) {

    // Answer:
    e.getCause().printStackTrace();
} catch (Exception e) {

    // generic exception handling
    e.printStackTrace();
}
Rocky Inde
sumber
1
Terima kasih; ini telah membantu saya menyadari bahwa masalah saya bukan dalam refleksi itu sendiri, tetapi dalam metode yang dipanggil.
Jose Gómez
3

Ini menggambarkan sesuatu seperti,

InvocationTargetException adalah pengecualian yang diperiksa yang membungkus pengecualian yang dilemparkan oleh metode atau konstruktor yang dipanggil. Pada rilis 1.4, pengecualian ini telah dipasang untuk menyesuaikan dengan mekanisme rantai pengecualian-tujuan umum. "Pengecualian target" yang disediakan pada waktu konstruksi dan diakses melalui metode getTargetException () sekarang dikenal sebagai penyebabnya, dan dapat diakses melalui metode Throwable.getCause (), serta "metode legacy" yang disebutkan sebelumnya.

Sazzad Hissain Khan
sumber
2

Anda dapat membandingkan dengan Kelas pengecualian asli menggunakan metode getCause () seperti ini:

try{
  ...
} catch(Exception e){
   if(e.getCause().getClass().equals(AssertionError.class)){
      // handle your exception  1
   } else {
      // handle the rest of the world exception 
   }
} 
Mehdi
sumber
1

Saya memiliki java.lang.reflect.InvocationTargetExceptionkesalahan dari pernyataan yang memanggil objek logger di eksternal classdi dalam try/ catchblok di saya class.

Melangkah melalui kode di Eclipse debugger & melayang mouse di atas pernyataan logger saya melihat logger objectitu null(beberapa konstanta eksternal perlu dipakai di bagian paling atas dari saya class).

Stuart Cardall
sumber
0

Pengecualian ini dilemparkan jika metode yang mendasarinya (metode yang disebut menggunakan Refleksi) melempar pengecualian.

Jadi jika metode, yang telah dipanggil oleh API refleksi, melempar pengecualian (seperti misalnya pengecualian runtime), API refleksi akan membungkus pengecualian menjadi InvocationTargetException.

Nikhil Kumar
sumber
0

Saya menghadapi masalah yang sama. Saya menggunakan e.getCause (). GetCause () kemudian saya menemukan bahwa itu karena parameter yang salah yang saya lewati. Ada nullPointerException dalam mengambil nilai dari salah satu parameter. Semoga ini bisa membantu Anda.

Deepak Vajpayee
sumber
-2
  1. Daftar semua file jar dari mode Eclipse Navigator
  2. Verifikasi bahwa semua file jar berada dalam mode biner
Manik
sumber
4
Bagaimana tepatnya Anda memverifikasi file jar dalam mode biner dengan melihatnya di Navigator?
William
@ William kau membuatku tertawa hahaha. Jawaban orang ini harus diturunkan.
Karim Manaouil
-7

Kesalahan hilang setelah saya melakukan Clean-> Run xDoclet-> Run xPackaging.

Di ruang kerja saya, di ecllipse.

Ashutosh Singh
sumber