apa itu akses reflektif ilegal

126

Ada banyak pertanyaan seputar akses reflektif ilegal di Java 9.

Sekarang apa yang tidak dapat saya temukan karena semua yang dimuntahkan Google adalah orang-orang yang mencoba mengatasi pesan kesalahan, adalah apa sebenarnya akses reflektif ilegal itu.

Jadi pertanyaan saya cukup sederhana adalah:

Apa yang mendefinisikan akses reflektif ilegal dan keadaan apa yang memicu peringatan?

Saya telah mengumpulkan bahwa itu ada hubungannya dengan prinsip-prinsip enkapsulasi yang diperkenalkan di Java 9, tetapi bagaimana semuanya hang bersama dan apa yang memicu peringatan dalam skenario apa yang tidak dapat saya temukan penjelasannya.

Tschallacka
sumber
2
ini mungkin menarik bagi Anda juga: jaxenter.com/jdk-9-replace-permit-illegal-access-134180.html
Edwin

Jawaban:

54

Terlepas dari pemahaman tentang akses antar modul dan paketnya masing-masing. Saya percaya inti dari itu terletak pada Sistem Modul # Santai-kuat-enkapsulasi dan saya hanya akan memilih bagian yang relevan untuk mencoba dan menjawab pertanyaan itu.

Apa yang mendefinisikan akses reflektif ilegal dan keadaan apa yang memicu peringatan?

Untuk membantu migrasi ke Java-9, enkapsulasi yang kuat dari modul dapat dilonggarkan.

  • Implementasi dapat menyediakan akses statis , yaitu bytecode yang dikompilasi.

  • Dapat menyediakan sarana untuk menjalankan sistem waktu berjalannya dengan satu atau lebih paket dari satu atau lebih modulnya yang terbuka untuk kode di semua modul yang tidak disebutkan namanya , yaitu ke kode pada jalur kelas. Jika sistem run-time dipanggil dengan cara ini, dan jika dengan melakukan itu beberapa pemanggilan API refleksi berhasil, jika tidak maka akan gagal.

Dalam kasus seperti itu, Anda sebenarnya akhirnya membuat akses reflektif yang "ilegal" karena dalam dunia modular murni Anda tidak dimaksudkan untuk melakukan akses tersebut.

Bagaimana semuanya saling terkait dan apa yang memicu peringatan dalam skenario apa?

Pelonggaran enkapsulasi ini dikontrol pada waktu proses oleh opsi peluncur baru --illegal-accessyang sama dengan default di Java9 permit. The permitmodus Memastikan

Operasi akses reflektif pertama ke paket seperti itu menyebabkan peringatan dikeluarkan, tetapi tidak ada peringatan yang dikeluarkan setelah titik itu. Peringatan tunggal ini menjelaskan cara mengaktifkan peringatan lebih lanjut. Peringatan ini tidak dapat diredam.

Mode dapat dikonfigurasi dengan nilai debug(pesan serta pelacakan tumpukan untuk setiap akses tersebut), warn(pesan untuk setiap akses tersebut), dan deny(menonaktifkan operasi tersebut).


Beberapa hal untuk di-debug dan diperbaiki pada aplikasi adalah: -

  • Jalankan dengan --illegal-access=denyuntuk mengetahui tentang dan menghindari membuka paket dari satu modul ke modul lain tanpa deklarasi modul termasuk direktif ( opens) atau penggunaan eksplisit--add-opens argumen VM.
  • Referensi statis dari kode yang dikompilasi ke API internal JDK dapat diidentifikasi menggunakan jdepsalat dengan --jdk-internalsopsi tersebut

Pesan peringatan yang dikeluarkan ketika operasi akses reflektif ilegal terdeteksi memiliki bentuk berikut:

WARNING: Illegal reflective access by $PERPETRATOR to $VICTIM

dimana:

$PERPETRATOR adalah nama jenis yang sepenuhnya memenuhi syarat yang berisi kode yang memanggil operasi reflektif yang dimaksud ditambah sumber kode (yaitu, jalur file JAR), jika tersedia, dan

$VICTIM adalah string yang menjelaskan anggota yang diakses, termasuk nama yang sepenuhnya memenuhi syarat dari tipe penutup

Pertanyaan untuk contoh peringatan seperti itu: = JDK9: Operasi akses reflektif ilegal telah terjadi. org.python.core.PySystemState

Terakhir dan catatan penting, saat mencoba memastikan bahwa Anda tidak menghadapi peringatan seperti itu dan aman di masa depan, yang perlu Anda lakukan adalah memastikan modul Anda tidak membuat akses reflektif ilegal tersebut. :)

Naman
sumber
21

Ada artikel Oracle yang saya temukan tentang sistem modul Java 9

Secara default, tipe dalam modul tidak dapat diakses oleh modul lain kecuali itu adalah tipe publik dan Anda mengekspor paketnya. Anda hanya mengekspos paket yang ingin Anda tampilkan. Dengan Java 9, ini juga berlaku untuk refleksi.

Seperti yang ditunjukkan di https://stackoverflow.com/a/50251958/134894 , perbedaan antara AccessibleObject#setAccessibleuntuk JDK8 dan JDK9 bersifat instruktif. Secara khusus, JDK9 menambahkan

Metode ini dapat digunakan oleh pemanggil di kelas C untuk mengaktifkan akses ke anggota yang mendeklarasikan kelas D jika salah satu dari berikut ini ditahan:

  • C dan D berada di modul yang sama.
  • Anggota adalah publik dan D publik dalam sebuah paket yang modul yang berisi ekspor D setidaknya ke modul yang berisi C.
  • Anggota dilindungi statis, D publik dalam paket yang modul yang berisi ekspor D setidaknya ke modul yang berisi C, dan C adalah subkelas D.
  • D ada dalam sebuah paket dimana modul yang berisi D terbuka untuk setidaknya modul yang berisi C. Semua paket dalam modul yang tidak dinamai dan terbuka terbuka untuk semua modul sehingga metode ini selalu berhasil ketika D berada dalam modul yang tidak dinamai atau terbuka.

yang menyoroti pentingnya modul dan ekspornya (di Java 9)

ptomli.dll
sumber
2
Jadi jika saya membaca artikel itu dengan benar mengubah properti privat di kelas yang diekspor tidak dapat dilakukan. Hanya properti yang dilindungi dan publik yang dapat dimodifikasi. Sekarang saya tidak terlalu peduli tentang ekspor internal java, tetapi lebih banyak tentang perpustakaan pihak ke-3 di mana saya terkadang memerlukan akses ke variabel pribadi untuk disetel ke nilai tertentu. Itu tidak akan mungkin lagi dalam skema ini jika itu akan mendefinisikan dirinya sebagai modul, apakah itu benar?
Tschallacka
1
Saya tidak memiliki pengalaman langsung dengan itu, tetapi itu akan menjadi pemahaman saya, dan membaca di samping artikel yang disebutkan di tempat lain ( jaxenter.com/jdk-9-replace-permit-illegal-access-134180.html ) yang sepertinya kasus. Luncurkan JVM Anda dengan –illegal-access=permit...
ptomli
1
Nah itu akan membuat segalanya lebih menarik mencoba untuk membuat sesuatu bekerja untuk beberapa hal ketika mereka memutuskan untuk pergi ke cara modul. Waktu yang sangat menyenangkan di depan.
Tschallacka
1
Untuk berbagai nilaifun
ptomli
Saya menerima jawaban lain karena memberikan lebih banyak penjelasan dan lebih merupakan jawaban atas pertanyaan tetapi sayangnya saya tidak dapat menerima dua jawaban.
Tschallacka
13

Lihat saja setAccessible()metode yang digunakan untuk mengaksesprivate bidang dan metode:

https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible-boolean-

https://docs.oracle.com/javase/9/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible-boolean-

Sekarang ada lebih banyak kondisi yang diperlukan agar metode ini berfungsi. Satu-satunya alasan mengapa ia tidak merusak hampir semua perangkat lunak lama adalah bahwa modul yang dibuat secara otomatis dari JAR biasa sangat permisif (buka dan ekspor semuanya untuk semua orang).

pengguna158037
sumber
1

Jika Anda ingin menggunakan opsi add-open, berikut adalah perintah untuk menemukan modul mana yang menyediakan paket mana ->

java --list-modules | tr @ " " | awk '{ print $1 }' | xargs -n1 java -d

nama modul akan ditampilkan dengan @ sedangkan nama paket tanpa itu

CATATAN: diuji dengan JDK 11

PENTING: jelas lebih baik daripada penyedia paket tidak melakukan akses ilegal

Carlos Saltos
sumber