1. Không thể truy cập mục tiêu, số nhận dạng 'bean' được giải quyết thành null
Điều này có nghĩa là bản thân bean được quản lý không thể tìm thấy bằng chính xác định danh đó (tên bean được quản lý) trong EL như vậy #{bean}
.
Xác định nguyên nhân có thể được chia thành ba bước:
a. Ai đang quản lý đậu?
b. Tên đậu được quản lý (mặc định) là gì?
c. Lớp đậu ủng hộ ở đâu?
1a. Ai đang quản lý đậu?
Bước đầu tiên sẽ là kiểm tra khung quản lý bean nào chịu trách nhiệm quản lý thể hiện bean. Có phải là JSF thông qua @ManagedBean
? Hay là CDI thông qua @Named
? Hay là mùa xuân qua @Component
? Bạn có thể chắc chắn rằng bạn không trộn nhiều chú thích cụ thể của khung quản lý bean trên cùng một lớp bean sao lưu không? Ví dụ @Named @Component
, hoặc @Named @ManagedBean
, hoặc @ManagedBean @Component
. Cái này sai. Bean phải được quản lý bởi tối đa một khung quản lý bean và khung đó phải được cấu hình đúng. Nếu bạn chưa có ý tưởng nào để chọn, hãy tìm đến Backing bean (@ManagedBean) hoặc CDI Beans (@ Named)? và tích hợp Spring JSF: làm thế nào để tiêm một thành phần / dịch vụ Spring trong bean được quản lý JSF?
Trong trường hợp đó là JSF , người quản lý bean thông qua @ManagedBean
, thì bạn cần đảm bảo những điều sau:
Các faces-config.xml
tuyên bố gốc tương thích với JSF 2.0. Vì vậy, các tập tin XSD và version
phải ít nhất định JSF 2.0 hoặc cao hơn và do đó không 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">
Đối với JSF 2.1, chỉ cần thay thế 2_0
và 2.0
bằng 2_1
và 2.1
tương ứng.
Nếu bạn đang sử dụng JSF 2.2 trở lên, thì hãy đảm bảo rằng bạn đang sử dụng xmlns.jcp.org
không gian tên thay vì ở java.sun.com
khắp mọi nơi.
<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">
Đối với JSF 2.3, chỉ cần thay thế 2_2
và 2.2
bằng 2_3
và 2.3
tương ứng.
Bạn đã không vô tình nhập javax.annotation.ManagedBean
thay vì javax.faces.bean.ManagedBean
. Xem ra với IDE tự động hoàn thành, Eclipse được biết là tự động đề xuất cái sai là mục đầu tiên trong danh sách.
- Bạn đã không ghi đè mục nhập
@ManagedBean
kiểu JSF 1.x <managed-bean>
trong faces-config.xml
cùng một lớp bean sao lưu cùng với tên bean được quản lý khác. Điều này sẽ có quyền ưu tiên hơn @ManagedBean
. Đăng ký một bean được quản lý faces-config.xml
là không cần thiết kể từ JSF 2.0, chỉ cần xóa nó.
- Đường dẫn lớp thời gian chạy của bạn sạch sẽ và không có các bản sao trong các JAR liên quan đến API của API. Hãy chắc chắn rằng bạn không trộn lẫn nhiều triển khai JSF (Mojarra và MyFaces). Đảm bảo rằng bạn không cung cấp tệp JAR API Java hoặc thậm chí Java EE khác cùng với ứng dụng web khi bộ chứa đích đã gói API JSF ra khỏi hộp. Xem thêm phần "Cài đặt JSF" trên trang wiki JSF của chúng tôi để biết hướng dẫn cài đặt JSF. Trong trường hợp bạn có ý định nâng cấp JSF được đóng gói từ WAR thay vì trong chính container, hãy đảm bảo rằng bạn đã hướng dẫn bộ chứa đích sử dụng API / hàm JSF được đóng gói WAR.
- Nếu bạn đang đóng gói các hạt đậu được quản lý JSF trong JAR, thì hãy đảm bảo rằng JAR có ít nhất tương thích với JSF 2.0
/META-INF/faces-config.xml
. Xem thêm Làm thế nào để tham khảo các bean được quản lý JSF được cung cấp trong tệp JAR?
Nếu bạn đang thực sự sử dụng JSF 1.x jurassic, và bạn không thể nâng cấp, sau đó bạn cần phải đăng ký đậu qua <managed-bean>
trong faces-config.xml
thay vì @ManagedBean
. Đừng quên sửa đường dẫn xây dựng dự án của bạn để bạn không còn thư viện JSF 2.x nữa (để @ManagedBean
chú thích sẽ không biên dịch thành công một cách khó hiểu).
Trong trường hợp đó là CDI , người quản lý bean thông qua @Named
, thì bạn cần đảm bảo những điều sau:
CDI 1.0 (Java EE 6) yêu cầu một /WEB-INF/beans.xml
tệp để bật CDI trong WAR. Nó có thể trống hoặc nó có thể có nội dung sau:
<?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) không có bất kỳ beans.xml
hoặc một beans.xml
tệp trống nào hoặc tương thích với CDI 1.0 ở trên beans.xml
sẽ hoạt động giống như CDI 1.0. Khi có một CDI 1.1 tương thích beans.xml
với một rõ ràng version="1.1"
, sau đó nó sẽ theo mặc định chỉ đăng ký @Named
đậu với một CDI phạm vi chú thích rõ ràng như @RequestScoped
, @ViewScoped
, @SessionScoped
, @ApplicationScoped
, vv Trong trường hợp bạn có ý định đăng ký tất cả đậu như CDI quản lý đậu, ngay cả những người không có rõ ràng Phạm vi CDI, sử dụng CDI 1.1 dưới đây tương thích /WEB-INF/beans.xml
với bean-discovery-mode="all"
bộ (mặc định là 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>
Khi sử dụng CDI 1.1+ với bean-discovery-mode="annotated"
(mặc định), hãy đảm bảo rằng bạn không vô tình nhập phạm vi JSF như javax.faces.bean.RequestScoped
thay vì phạm vi CDI javax.enterprise.context.RequestScoped
. Xem ra với IDE tự động hoàn thành.
- Khi sử dụng Mojarra 2.3.0-2.3.2 và CDI 1.1+ với
bean-discovery-mode="annotated"
(mặc định), thì bạn cần nâng cấp Mojarra lên phiên bản 2.3.3 hoặc mới hơn do lỗi . Trong trường hợp bạn không thể nâng cấp, sau đó bạn cần hoặc để thiết lập bean-discovery-mode="all"
trong beans.xml
, hoặc để đưa cụ JSF 2.3 @FacesConfig
chú thích trên một lớp tùy ý trong WAR (thường một số loại của một ứng dụng scoped lớp khởi động).
- Các container không phải Java EE như Tomcat và Jetty không được gửi kèm theo CDI. Bạn cần phải cài đặt nó bằng tay. Đó là một công việc nhiều hơn một chút so với chỉ thêm thư viện JAR (s). Đối với Tomcat, hãy đảm bảo rằng bạn làm theo hướng dẫn trong câu trả lời này: Cách cài đặt và sử dụng CDI trên Tomcat?
- Classpath thời gian chạy của bạn sạch sẽ và không có các bản sao trong các JAR liên quan đến API CDI. Đảm bảo rằng bạn không trộn lẫn nhiều triển khai CDI (Weld, OpenWebBeans, v.v.). Đảm bảo rằng bạn không cung cấp tệp JAR CDI hoặc thậm chí Java EE khác cùng với ứng dụng web khi bộ chứa đích đã gói API CDI ra khỏi hộp.
Nếu bạn đang đóng gói các hạt đậu được quản lý CDI cho các khung nhìn JSF trong JAR, thì hãy đảm bảo rằng JAR có ít nhất một giá trị hợp lệ /META-INF/beans.xml
(có thể được giữ trống).
Trong trường hợp đó là Spring , người quản lý bean thông qua @Component
, thì bạn cần đảm bảo những điều sau:
Spring đang được cài đặt và tích hợp theo tài liệu của nó . Quan trọng, bạn cần ít nhất có cái này trong web.xml
:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Và điều này trong faces-config.xml
:
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
(trên đây là tất cả những gì tôi biết liên quan đến Mùa xuân - Tôi không làm Mùa xuân - thoải mái chỉnh sửa / nhận xét với các nguyên nhân liên quan đến Mùa xuân có thể xảy ra khác; ví dụ: một số sự cố liên quan đến cấu hình XML)
Trong trường hợp đó là một thành phần lặp lại của những người quản lý (lồng) đậu qua nó var
thuộc tính (ví dụ như <h:dataTable var="item">
, <ui:repeat var="item">
, <p:tabView var="item">
, vv) và bạn thực sự có một "Target Unreachable, nhận dạng 'mục' quyết tâm vô giá trị", thì bạn cần phải chắc chắn rằng những điều sau đây :
Điều #{item}
này không được tham chiếu trong binding
attribtue của bất kỳ thành phần con nào. Điều này không chính xác vì binding
thuộc tính chạy trong thời gian xây dựng chế độ xem, không phải trong thời gian hiển thị chế độ xem. Hơn nữa, về mặt vật lý chỉ có một thành phần trong cây thành phần được sử dụng lại đơn giản trong mỗi vòng lặp. Nói cách khác, bạn thực sự nên sử dụng binding="#{bean.component}"
thay vì binding="#{item.component}"
. Nhưng tốt hơn nhiều là loại bỏ hoàn toàn bining thành phần đậu và điều tra / hỏi phương pháp thích hợp cho vấn đề bạn nghĩ để giải quyết theo cách này. Xem thêm Làm thế nào để thuộc tính 'ràng buộc' hoạt động trong JSF? Nên sử dụng khi nào và như thế nào?
1b. Tên đậu được quản lý (mặc định) là gì?
Bước thứ hai sẽ là kiểm tra tên đậu được quản lý đã đăng ký. JSF và Spring sử dụng các quy ước tuân thủ đặc tả JavaBeans trong khi CDI có các ngoại lệ tùy thuộc vào phiên bản / hàm CDI.
Một FooBean
lớp đậu ủng hộ như dưới đây,
@Named
public class FooBean {}
trong tất cả các khung quản lý bean sẽ có một tên bean được quản lý mặc định #{fooBean}
, theo đặc tả của JavaBeans.
Một FOOBean
lớp đậu ủng hộ như dưới đây,
@Named
public class FOOBean {}
có tên lớp không đủ tiêu chuẩn bắt đầu bằng ít nhất hai chữ viết hoa trong JSF và Spring có tên bean được quản lý mặc định của chính xác tên lớp không đủ tiêu chuẩn #{FOOBean}
, cũng tuân thủ đặc tả JavaBeans. Trong CDI, đây cũng là trường hợp trong các phiên bản Weld được phát hành trước tháng 6 năm 2015, nhưng không phải trong các phiên bản Weld được phát hành sau tháng 6 năm 2015 (2.2,14 / 2.3.0.B1 / 3.0.0.A9) cũng như trong OpenWebBeans do sự giám sát trong Thông số CDI . Trong các phiên bản Weld đó và trong tất cả các phiên bản OWB, nó chỉ có ký tự đầu tiên được hạ thấp #{fOOBean}
.
Nếu bạn đã chỉ định rõ ràng một tên bean được quản lý foo
như dưới đây,
@Named("foo")
public class FooBean {}
hoặc tương đương với @ManagedBean(name="foo")
hoặc @Component("foo")
, sau đó nó sẽ chỉ có sẵn bằng #{foo}
và do đó không bằng #{fooBean}
.
1c. Lớp đậu ủng hộ ở đâu?
Bước thứ ba sẽ là kiểm tra lại nếu lớp bean dự phòng ở đúng vị trí trong tệp WAR được xây dựng và triển khai. Hãy chắc chắn rằng bạn đã thực hiện đầy đủ sạch, xây dựng lại, triển khai lại và khởi động lại dự án và máy chủ trong trường hợp bạn thực sự bận viết mã và nhấn F5 một cách thiếu kiên nhẫn trong trình duyệt. Nếu vẫn vô ích, hãy để hệ thống xây dựng tạo tệp WAR, sau đó bạn trích xuất và kiểm tra bằng công cụ ZIP. Biên soạn.class
của lớp bean sao lưu phải nằm trong cấu trúc gói của nó trong /WEB-INF/classes
. Hoặc, khi nó được đóng gói như một phần của mô-đun JAR, JAR chứa .class
tệp đã biên dịch phải nằm trong /WEB-INF/lib
đó, do đó không phải là EAR /lib
hoặc các nơi khác.
Nếu bạn đang sử dụng Eclipse, hãy đảm bảo rằng lớp bean dự phòng có trong src
và do đó không WebContent
, và đảm bảo rằng Project> Build Automatic được bật. Nếu bạn đang sử dụng Maven, hãy đảm bảo rằng lớp bean hậu thuẫn nằm trong src/main/java
và do đó không nằm trong src/main/resources
hoặc src/main/webapp
.
Nếu bạn đóng gói ứng dụng web như một phần của EAR với EJB + WAR (s), thì bạn cần đảm bảo rằng các lớp bean sao lưu nằm trong mô-đun WAR và do đó không phải trong mô-đun EAR cũng như mô-đun EJB. Tầng doanh nghiệp (EJB) phải không có bất kỳ tạo phẩm nào liên quan đến tầng web (WAR), để tầng doanh nghiệp có thể được sử dụng lại trên nhiều tầng web khác nhau (JSF, JAX-RS, JSP / Servlet, v.v.).
2. Không thể truy cập mục tiêu, 'thực thể' được trả về null
Điều này sôi xuống với tài sản lồng nhauentity
như trong #{bean.entity.property}
trả lại null
. Điều này thường chỉ hiển thị khi JSF cần đặt giá trị cho property
thông qua một thành phần đầu vào như bên dưới, trong khi #{bean.entity}
thực tế được trả về null
.
<h:inputText value="#{bean.entity.property}" />
Bạn cần đảm bảo rằng bạn đã chuẩn bị trước thực thể mô hình trong một @PostConstruct
hoặc <f:viewAction>
phương thức hoặc có lẽ là một add()
phương thức hành động trong trường hợp bạn đang làm việc với danh sách CRUD và / hoặc hộp thoại trên cùng một chế độ xem.
@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();
}
// ...
}
Như tầm quan trọng của @PostConstruct
; làm điều này trong một hàm tạo thông thường sẽ thất bại trong trường hợp bạn đang sử dụng khung quản lý bean sử dụng proxy , chẳng hạn như CDI. Luôn luôn sử dụng @PostConstruct
để hook khi khởi tạo thể hiện bean được quản lý (và sử dụng @PreDestroy
để hook khi phá hủy thể hiện bean được quản lý). Ngoài ra, trong một hàm tạo, bạn sẽ không có quyền truy cập vào bất kỳ phụ thuộc được chèn nào, hãy xem NullPulumException trong khi cố gắng truy cập @Inject bean trong hàm tạo .
Trong trường hợp entityId
được cung cấp qua <f:viewParam>
, bạn cần sử dụng <f:viewAction>
thay vì @PostConstruct
. Xem thêm Khi nào nên sử dụng f: viewAction / preRenderView so với PostConstruct?
Bạn cũng cần đảm bảo rằng bạn bảo tồn null
mô hình không trong quá trình postback trong trường hợp bạn chỉ tạo nó trong một add()
phương thức hành động. Dễ nhất là đặt bean trong phạm vi xem. Xem thêm Làm thế nào để chọn phạm vi đậu đúng?
3. Không thể truy cập mục tiêu, 'null' được trả về null
Điều này thực sự có cùng nguyên nhân với # 2, chỉ có việc triển khai EL (cũ hơn) được sử dụng có phần lỗi trong việc giữ tên thuộc tính để hiển thị trong thông báo ngoại lệ, cuối cùng được hiển thị không chính xác là 'null'. Điều này chỉ làm cho việc gỡ lỗi và sửa lỗi khó hơn một chút khi bạn có khá nhiều thuộc tính lồng nhau như vậy#{bean.entity.subentity.subsubentity.property}
.
Giải pháp vẫn giống nhau: đảm bảo rằng thực thể lồng nhau trong câu hỏi không null
, trong tất cả các cấp.
4. Không thể truy cập mục tiêu, '' 0 '' được trả về null
Điều này cũng có cùng nguyên nhân với # 2, chỉ có việc triển khai EL (cũ hơn) đang được sử dụng là lỗi trong việc hình thành thông báo ngoại lệ. Điều này chỉ hiển thị khi bạn sử dụng ký hiệu dấu ngoặc []
trong EL như trong #{bean.collection[index]}
đó #{bean.collection}
bản thân nó là không rỗng, nhưng mục tại chỉ mục được chỉ định không tồn tại. Một thông điệp như vậy sau đó phải được hiểu là:
Không thể truy cập mục tiêu, 'bộ sưu tập [0]' trả về null
Giải pháp cũng giống như # 2: đảm bảo rằng bộ sưu tập có sẵn.
5. Không thể truy cập mục tiêu, 'ngoặcSuffix' trả về null
Điều này thực sự có cùng nguyên nhân với số 4, chỉ có việc triển khai EL (cũ hơn) được sử dụng có phần lỗi trong việc duy trì chỉ số lặp để hiển thị trong thông báo ngoại lệ, cuối cùng được hiển thị không chính xác là 'ngoặcSuffix' thực sự là ký tự ]
. Điều này chỉ làm cho việc gỡ lỗi và sửa lỗi khó hơn một chút khi bạn có nhiều mục trong bộ sưu tập.
Các nguyên nhân có thể khác của javax.el.PropertyNotFoundException
: