Navigating the PropertyNotFoundException: Evaluating MethodExpressions in Composite Components
Composite components in JSF offer a powerful way to encapsulate UI elements and logic, enhancing code reusability and maintainability. However, developers often encounter the dreaded PropertyNotFoundException
when attempting to evaluate a MethodExpression
within a composite component. This error arises when the component cannot locate the specified method or property.
Let's break down the situation and provide a clear solution.
Scenario: The PropertyNotFoundException
Imagine you're building a reusable RatingComponent
to display and update a rating value. The component uses a MethodExpression
to bind the rating value to a backing bean method:
// RatingComponent.xhtml
<h:inputText value="#{ratingBean.rating}"/>
<h:commandButton value="Submit" action="#{ratingBean.submitRating}"/>
Now, when you use the RatingComponent
in a different JSF page, you might see the following error:
javax.el.PropertyNotFoundException: Target Unreachable, identifier 'ratingBean' resolved to null
This PropertyNotFoundException
arises because the ratingBean
is not accessible within the composite component's scope.
The Root Cause: Scope Mismatch
The core issue lies in the way JSF handles scopes and method expressions within composite components. By default, a composite component creates its own scope, isolated from the scope of the page where it's used. This means that references like #{ratingBean}
inside the component's template are evaluated within the component's scope, not the page's scope.
The Solution: Injecting Dependencies
To correctly access the ratingBean
in your composite component, we need to inject it using a MethodExpression
that points to the page's scope:
// RatingComponent.xhtml
<cc:interface>
<cc:attribute name="ratingBean" required="true" type="java.lang.Object"/>
</cc:interface>
<h:inputText value="#{cc.attrs.ratingBean.rating}"/>
<h:commandButton value="Submit" action="#{cc.attrs.ratingBean.submitRating}"/>
Here's what's happening:
- We declare an attribute named
ratingBean
in the composite component's interface, marking it as required. This ensures that the page providing the component must supply a value forratingBean
. - In the template, we use
cc.attrs.ratingBean
to access the injectedratingBean
object. This expression retrieves the attribute value passed from the page, allowing us to access its properties and methods.
Understanding the cc.attrs
Object
The cc.attrs
object serves as a bridge between the composite component's internal scope and the page's scope. It provides access to all the attributes passed to the component. This allows you to share data and logic between the component and the page without introducing global dependencies.
Key Takeaways
- Scope Awareness: Understanding the difference between composite component scope and page scope is crucial to avoiding
PropertyNotFoundExceptions
. - Injecting Dependencies: Use
cc.attrs
to access properties and methods provided by the page when working withMethodExpressions
inside composite components. - Component Reusability: By following these best practices, you can create robust and reusable composite components that seamlessly integrate into your JSF applications.
Additional Resources
- JSF 2.0 Composite Components
- JSF 2.0 Composite Components
- JSF 2.0 Composite Components: Accessing backing bean properties
By understanding the nuances of scope and dependency injection, you can overcome the PropertyNotFoundException
and craft powerful, reusable composite components.