1. Target Tidak Dapat Dicapai, pengidentifikasi 'kacang' diselesaikan ke nol
Ini bermuara pada bahwa contoh kacang yang dikelola itu sendiri tidak dapat ditemukan dengan persis pengenal (nama kacang yang dikelola) di EL seperti itu #{bean}
.
Mengidentifikasi penyebabnya dapat dipecah menjadi tiga langkah:
Sebuah. Siapa yang mengelola kacang?
b. Apa nama kacang yang dikelola (default)?
c. Di mana kelas kacang dukungan?
1a. Siapa yang mengelola kacang?
Langkah pertama adalah memeriksa kerangka kerja manajemen kacang mana yang bertanggung jawab untuk mengelola instance kacang. Apakah ini JSF via @ManagedBean
? Atau melalui CDI@Named
? Atau musim semi lewat @Component
? Bisakah Anda memastikan bahwa Anda tidak mencampur anotasi kerangka kerja beberapa manajemen kacang pada kelas kacang dukungan yang sama? Misalnya @Named @Component
, atau @Named @ManagedBean
, atau @ManagedBean @Component
. Ini salah. Kacang harus dikelola oleh paling banyak satu kerangka kerja pengelolaan kacang dan kerangka kerja itu harus dikonfigurasi dengan benar. Jika Anda tidak tahu harus memilih mana, pergilah ke Backing beans (@ManagedBean) atau CDI Beans (@Named)? dan integrasi Spring JSF: bagaimana cara menyuntikkan komponen / layanan Spring dalam kacang yang dikelola JSF?
Jika JSF yang mengelola kacang melalui @ManagedBean
, maka Anda perlu memastikan hal-hal berikut:
The faces-config.xml
akar deklarasi kompatibel dengan JSF 2.0. Jadi file XSD dan version
harus setidaknya menentukan JSF 2.0 atau lebih tinggi dan dengan demikian tidak 1.x.
<faces-config
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">
Untuk JSF 2.1, cukup ganti 2_0
dan 2.0
dengan 2_1
dan 2.1
masing - masing.
Jika Anda menggunakan JSF 2.2 atau lebih tinggi, pastikan Anda menggunakan xmlns.jcp.org
ruang nama alih-alih dari java.sun.com
semua tempat.
<faces-config
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
version="2.2">
Untuk JSF 2.3, cukup ganti 2_2
dan 2.2
dengan 2_3
dan 2.3
masing - masing.
Anda tidak sengaja mengimpor javax.annotation.ManagedBean
bukan javax.faces.bean.ManagedBean
. Hati-hati dengan IDE autocomplete, Eclipse dikenal untuk menyarankan secara otomatis yang salah sebagai item pertama dalam daftar.
- Anda tidak mengganti
@ManagedBean
dengan <managed-bean>
entri gaya JSF 1.x di faces-config.xml
pada kelas kacang dukungan yang sama bersama dengan nama kacang terkelola yang berbeda. Yang ini akan lebih diutamakan @ManagedBean
. Mendaftarkan kacang terkelola faces-config.xml
tidak diperlukan sejak JSF 2.0, hapus saja.
- Classpath runtime Anda bersih dan bebas dari duplikat di JAR terkait JSF API. Pastikan Anda tidak mencampur beberapa implementasi JSF (Mojarra dan MyFaces). Pastikan Anda tidak menyediakan file JSF JSF atau Java EE API lainnya di webapp ketika wadah target sudah bundel API JSF di luar kotak. Lihat juga "Memasang JSF" dari halaman wiki JSF kami untuk instruksi pemasangan JSF. Jika Anda berniat untuk meningkatkan JSF yang dibundel dalam wadah dari WAR pada dan bukan di dalam wadah itu sendiri, pastikan Anda telah menginstruksikan wadah target untuk menggunakan JSF API / impl yang dibundel dengan WAR.
- Jika Anda mengemas kacang yang dikelola JSF dalam JAR, maka pastikan bahwa JAR memiliki setidaknya JSF 2.0 yang kompatibel
/META-INF/faces-config.xml
. Lihat juga Bagaimana merujuk kacang yang dikelola JSF yang disediakan dalam file JAR?
Jika Anda benar-benar menggunakan JSF 1.x jurassic, dan Anda tidak dapat meng-upgrade, maka Anda harus mendaftar kacang melalui <managed-bean>
di faces-config.xml
bukannya @ManagedBean
. Jangan lupa untuk memperbaiki path build proyek Anda sehingga Anda tidak memiliki pustaka JSF 2.x lagi (sehingga @ManagedBean
anotasi tidak akan berhasil dikompilasi secara membingungkan).
Jika CDI- lah yang mengelola biji melalui @Named
, maka Anda perlu memastikan hal-hal berikut:
CDI 1.0 (Java EE 6) membutuhkan /WEB-INF/beans.xml
file untuk mengaktifkan CDI di WAR. Itu bisa kosong atau hanya memiliki konten berikut:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>
CDI 1.1 (Java EE 7) tanpa beans.xml
, atau beans.xml
file kosong , atau dengan CDI 1.0 yang kompatibel beans.xml
akan berperilaku sama dengan CDI 1.0. Ketika ada CDI 1.1 kompatibel beans.xml
dengan eksplisit version="1.1"
, maka akan secara default hanya mendaftar @Named
kacang dengan sebuah CDI lingkup penjelasan eksplisit seperti @RequestScoped
, @ViewScoped
, @SessionScoped
, @ApplicationScoped
, dll Dalam kasus Anda berniat untuk mendaftarkan semua kacang sebagai CDI dikelola kacang, bahkan mereka tanpa eksplisit Cakupan CDI, gunakan CDI 1.1 yang kompatibel /WEB-INF/beans.xml
dengan bean-discovery-mode="all"
set di bawah ini (standarnya adalah bean-discovery-mode="annotated"
).
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="all">
</beans>
Saat menggunakan CDI 1.1+ dengan bean-discovery-mode="annotated"
(default), pastikan Anda tidak secara tidak sengaja mengimpor lingkup JSF seperti javax.faces.bean.RequestScoped
bukan lingkup CDI javax.enterprise.context.RequestScoped
. Hati-hati dengan IDE autocomplete.
- Saat menggunakan Mojarra 2.3.0-2.3.2 dan CDI 1.1+ dengan
bean-discovery-mode="annotated"
(default), maka Anda perlu memutakhirkan Mojarra ke 2.3.3 atau lebih baru karena bug . Dalam kasus Anda tidak dapat meng-upgrade, maka Anda perlu baik untuk set bean-discovery-mode="all"
di beans.xml
, atau untuk menempatkan JSF 2.3 spesifik @FacesConfig
penjelasan pada kelas sewenang-wenang dalam WAR (umumnya semacam aplikasi scoped kelas startup).
- Kontainer EE non-Jawa seperti Tomcat dan Jetty tidak dikirimkan bersama CDI. Anda harus menginstalnya secara manual. Ini sedikit lebih banyak pekerjaan daripada hanya menambahkan JAR perpustakaan. Untuk Tomcat, pastikan Anda mengikuti instruksi dalam jawaban ini: Bagaimana cara menginstal dan menggunakan CDI di Tomcat?
- Classpath runtime Anda bersih dan bebas dari duplikat dalam JAR terkait CDI. Pastikan Anda tidak mencampur beberapa implementasi CDI (Weld, OpenWebBeans, dll). Pastikan Anda tidak menyediakan CDI lain atau bahkan file Java EE API JAR di sepanjang webapp ketika wadah target sudah bundel dengan CDI API di luar kotak.
Jika Anda mengemas kacang yang dikelola CDI untuk tampilan JSF dalam JAR, maka pastikan bahwa JAR setidaknya memiliki yang valid /META-INF/beans.xml
(yang dapat disimpan kosong).
Jika Spring yang mengelola bean melalui @Component
, maka Anda perlu memastikan hal-hal berikut:
Spring sedang diinstal dan terintegrasi sesuai dokumentasinya . Yang penting, Anda setidaknya harus memiliki ini di web.xml
:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Dan ini di faces-config.xml
:
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
(di atas adalah semua yang saya tahu sehubungan dengan Spring - Saya tidak melakukan Spring - jangan ragu untuk mengedit / berkomentar dengan kemungkinan penyebab terkait Spring lainnya; misalnya beberapa masalah terkait konfigurasi XML)
Dalam kasus itu komponen repeater siapa yang mengelola (bersarang) kacang melalui nya var
atribut (misalnya <h:dataTable var="item">
, <ui:repeat var="item">
, <p:tabView var="item">
, dll) dan Anda benar-benar mendapat "Target Unreachable, identifier 'item' memutuskan untuk null", maka Anda perlu memastikan berikut ini :
Tidak #{item}
dirujuk dalam binding
atribut komponen anak apa pun. Ini tidak benar karena binding
atribut berjalan selama waktu pembuatan tampilan, bukan selama waktu tampilan render. Selain itu, secara fisik hanya ada satu komponen dalam komponen pohon yang hanya digunakan kembali selama setiap putaran iterasi. Dengan kata lain, Anda harus benar-benar menggunakan binding="#{bean.component}"
bukan binding="#{item.component}"
. Tetapi jauh lebih baik untuk menyingkirkan komponen bining sekaligus dan selidiki / tanyakan pendekatan yang tepat untuk masalah yang Anda pikir dapat memecahkan masalah ini. Lihat juga Bagaimana atribut 'mengikat' bekerja di JSF? Kapan dan bagaimana seharusnya digunakan?
1b. Apa nama kacang yang dikelola (default)?
Langkah kedua adalah memeriksa nama kacang yang dikelola terdaftar. Konvensi JSF dan Spring menggunakan spesifikasi JavaBeans sementara CDI memiliki pengecualian tergantung pada versi / implementasi CDI.
Kelas FooBean
backing bean seperti di bawah ini,
@Named
public class FooBean {}
akan di semua kerangka kerja manajemen bean memiliki nama default kacang dikelola #{fooBean}
, sesuai spesifikasi JavaBeans.
Kelas FOOBean
backing bean seperti di bawah ini,
@Named
public class FOOBean {}
yang nama kelasnya tidak memenuhi syarat dimulai dengan setidaknya dua ibukota akan di JSF dan Spring memiliki nama kacang dikelola standar persis nama kelas yang tidak memenuhi syarat #{FOOBean}
, juga sesuai dengan spesifikasi JavaBeans. Dalam CDI, ini juga merupakan kasus dalam versi Weld yang dirilis sebelum Juni 2015, tetapi tidak dalam versi Weld yang dirilis setelah Juni 2015 (2.2.14 / 2.3.0.B1 / 3.0.0.A9) atau di OpenWebBeans karena pengawasan di Spesifikasi CDI . Dalam versi Weld tersebut dan dalam semua versi OWB hanya dengan karakter pertama yang lebih rendah #{fOOBean}
.
Jika Anda telah secara eksplisit menentukan nama kacang yang dikelola foo
seperti di bawah ini,
@Named("foo")
public class FooBean {}
atau setara dengan @ManagedBean(name="foo")
atau @Component("foo")
, maka itu hanya akan tersedia oleh #{foo}
dan dengan demikian bukan oleh #{fooBean}
.
1c. Di mana kelas kacang dukungan?
Langkah ketiga adalah memeriksa ulang jika kelas backing bean berada di tempat yang tepat di file WAR yang dibangun dan digunakan. Pastikan Anda telah melakukan pembersihan, pembangunan kembali, penempatan ulang, dan restart proyek dan server seandainya Anda benar-benar sibuk menulis kode dan dengan tidak sabar menekan F5 di browser. Jika masih sia-sia, biarkan sistem build menghasilkan file WAR, yang kemudian Anda ekstrak dan periksa dengan alat ZIP. File yang dikompilasi .class
dari kelas backing bean harus berada dalam struktur paketnya di /WEB-INF/classes
. Atau, ketika itu dikemas sebagai bagian dari modul JAR, JAR yang berisi .class
file yang dikompilasi harus berada di /WEB-INF/lib
dan dengan demikian tidak misalnya EAR /lib
atau di tempat lain.
Jika Anda menggunakan Eclipse, pastikan kelas backing bean ada src
dan tidak WebContent
, dan pastikan Project> Build Automatically diaktifkan. Jika Anda menggunakan Maven, pastikan kelas backing bean berada di src/main/java
dan dengan demikian tidak di src/main/resources
atau src/main/webapp
.
Jika Anda mengemas aplikasi web sebagai bagian dari EAR dengan EJB + WAR (s), maka Anda perlu memastikan bahwa kelas kacang latar ada dalam modul WAR dan dengan demikian tidak dalam modul EAR atau modul EJB. Business tier (EJB) harus bebas dari artefak terkait web tier (WAR), sehingga tier bisnis dapat digunakan kembali di berbagai tingkatan web yang berbeda (JSF, JAX-RS, JSP / Servlet, dll).
2. Target Tidak Dapat Dicapai, 'entitas' dikembalikan nol
Ini bermuara pada bahwa properti bersarangentity
seperti dalam #{bean.entity.property}
dikembalikan null
. Ini biasanya hanya mengekspos ketika JSF perlu menetapkan nilai untuk property
melalui komponen input seperti di bawah ini, sedangkan yang #{bean.entity}
sebenarnya dikembalikan null
.
<h:inputText value="#{bean.entity.property}" />
Anda perlu memastikan bahwa Anda telah menyiapkan entitas model sebelumnya dalam suatu @PostConstruct
, atau <f:viewAction>
metode, atau mungkin add()
metode tindakan jika Anda bekerja dengan daftar CRUD dan / atau dialog pada tampilan yang sama.
@Named
@ViewScoped
public class Bean {
private Entity entity; // +getter (setter is not necessary).
@Inject
private EntityService entityService;
@PostConstruct
public void init() {
// In case you're updating an existing entity.
entity = entityService.getById(entityId);
// Or in case you want to create a new entity.
entity = new Entity();
}
// ...
}
Mengenai pentingnya @PostConstruct
; melakukan ini dalam konstruktor reguler akan gagal jika Anda menggunakan kerangka kerja manajemen kacang yang menggunakan proxy , seperti CDI. Selalu gunakan @PostConstruct
untuk mengaitkan inisialisasi instance kacang terkelola (dan gunakan @PreDestroy
untuk mengait pada penghancuran instance kacang terkelola). Selain itu, di konstruktor Anda belum memiliki akses ke dependensi yang disuntikkan, lihat juga NullPointerException saat mencoba mengakses @Inject bean di konstruktor .
Jika entityId
disediakan melalui <f:viewParam>
, Anda harus menggunakan <f:viewAction>
sebagai gantinya @PostConstruct
. Lihat juga Kapan menggunakan f: viewAction / preRenderView versus PostConstruct?
Anda juga perlu memastikan bahwa Anda mempertahankan non- null
model selama postback jika Anda membuatnya hanya dalam add()
metode tindakan. Cara termudah adalah menempatkan kacang dalam lingkup tampilan. Lihat juga Bagaimana memilih lingkup kacang yang tepat?
3. Target Tidak Dapat Dicapai, 'null' dikembalikan nol
Ini sebenarnya memiliki penyebab yang sama dengan # 2, hanya implementasi EL (lebih tua) yang digunakan agak buggy dalam menjaga nama properti untuk ditampilkan dalam pesan pengecualian, yang akhirnya salah diekspos sebagai 'nol'. Ini hanya membuat debugging dan memperbaiki sedikit lebih sulit ketika Anda memiliki beberapa properti bersarang seperti itu #{bean.entity.subentity.subsubentity.property}
.
Solusinya masih sama: pastikan entitas bersarang yang dimaksud tidak null
, di semua tingkatan.
4. Target Tidak Dapat Dicapai, '' 0 '' dikembalikan nol
Ini juga memiliki penyebab yang sama dengan # 2, hanya implementasi EL (lama) yang digunakan adalah buggy dalam merumuskan pesan pengecualian. Ini memperlihatkan hanya ketika Anda menggunakan notasi penjepit []
di EL seperti di #{bean.collection[index]}
mana #{bean.collection}
itu sendiri adalah non-nol, tetapi item pada indeks yang ditentukan tidak ada. Pesan seperti itu kemudian harus ditafsirkan sebagai:
Target Tidak Dapat Dicapai, 'koleksi [0]' dikembalikan nol
Solusinya juga sama dengan # 2: pastikan barang koleksi tersedia.
5. Target Tidak Dapat Dicapai, 'BracketSuffix' kembali nol
Ini sebenarnya memiliki penyebab yang sama dengan # 4, hanya implementasi EL (yang lebih tua) yang digunakan agak buggy dalam menjaga indeks iterasi untuk ditampilkan dalam pesan pengecualian, yang akhirnya salah diekspos sebagai 'BracketSuffix' yang benar-benar karakternya ]
. Ini hanya membuat proses debug dan perbaikan sedikit lebih sulit ketika Anda memiliki banyak item dalam koleksi.
Kemungkinan penyebab lain dari javax.el.PropertyNotFoundException
: