PropertyNotFoundException EL Expressions not resolving? - jsf

I have code similar to this in my facelet...
<c:foreach items=#{myBean.listOfA} var="a">
<c:foreach items=#{myBean.listOfB} var="b">
<c:set var="aName" value="#{a.name}">
<c:set var="component" value="#{b.associatedComponent(aName)}">//this wont resolve
//do stuff with component
</c:foreach>
</c:foreach>
myBean is a session scoped bean. Both A and B classes are maintained in lists inside the bean but are just model objects not managed beans.
That being said the method b.associatedComponent(a) I am assuming should resolve to b.getAssociatedComponent(A a) which I have checked many times. All methods are public. What can I do to make the method accessible to EL?
No matter what I try I get a PropertyNotFoundException on associatedComponent.
P.S. I also tried moving the method to the bean like this...
<c:set var="component" value="#{myBean.associatedComponent(b, aName)}">
This also does not work and throws the same PropertyNotFoundException.

This will not work, as the c:set tag expects a ValueExpression for the value attribute.
This means that you are only able to use properties - not methods.
If you use arguments like here #{b.associatedComponent(aName)} then what you have is a method call, not a property call. This however is a valid MethodExpression and can be used in places like the action attribute of a command link.
See the API documentation and spec for more details on this.

Related

How to execute a bean method inside foreach without button or link in jsf?

I am looping a list containing strings in foreach, so in every iteration the variable in foreach loop should be passed as a parameter to a bean method written inside the foreach loop. I searched many sites but everywhere I am finding solution that bean method cannot be executed without commandbutton or link. Is there any solution to execute bean method without any commandbutton or link.
<c:forEach var="name" items="#{bean.stringList}"
varStatus="loopCounter">
<!--I have to execute the method here passing "name" as parameter-->
</c:forEach>
Since EL 2.2 you can invoke non-getter methods with arguments. So you could use:
<c:forEach var="name" items="#{bean.stringList}"
varStatus="loopCounter">
<c:set var="dummy" value="#{bean.yourMethod(name)}" />
</c:forEach>
However, you are most likely are trying to solve something here that can be done in more elegant ways like a PhaseListener, a #PostConstruct method, a f:viewAction, etc.
See also
How to implement a PhaseListener which runs at end of lifecycle?
Why use #PostConstruct?
When to use f:viewAction / preRenderView versus PostConstruct?

Setting f:setPropertyActionListener value with a f:param value

I'm trying to use the setPropertyActionListener tag to set a value in my backing bean. However, it doesn't work as I expected.
Context: userService is an instance of my backing bean, which contains an int member, reqID. This, in turn, is the key to a map of objects that belong to a class called User. I'm trying to create a page that will list all instances of User, and provide a button to visit a separate view that shows that particular User's information. To do this, I'm attempting to set userService.reqID to the id of the chosen User so it can generate a reference to that user for the next view (which is done in the call userService.toUserInfo).
If I use the xhtml snippet below:
<ui:define name="content">
<h:form>
<h:panelGrid>
<ui:repeat value="#{userService.UserList.getUserList()}" var="user">
<li>
<h:outputText value="#{user.name}" />
<h:commandButton value="View details of #{user.name}" action="#{userService.toUserInfo}">
<f:param name="id" value="#{user.id}" />
<f:setPropertyActionListener target="#{userService.reqID}" value="#{id}"/>
</h:commandButton>
</li>
</ui:repeat>
</h:panelGrid>
</h:form>
</ui:define>
The tag does not appear to evaluate id correctly and I get a Null Pointer Exception.
Earlier, I tried changing my setPropertyActionListenerTag so it read out as:
<f:setPropertyActionListener target="#{userService.reqID}" value="id"/>
which gave me an error, because the tag was sending the string "id" as opposed to the int value of the parameter.
Is there some way to force f:setPropertyActionListener to evaluate the expression under value? Or is there another tag that will allow me to do this?
Also, is ui:param used appropriately here?
The <f:param> (and <ui:param>) doesn't work that way. The <f:param> is intented to add HTTP request parameters to outcome of <h:xxxLink> and <h:xxxButton> components, and to parameterize the message format in <h:outputFormat>. The <ui:param> is intented to pass Facelet context parameters to <ui:include>, <ui:decorate> and <ui:define>. Mojarra had the bug that it also behaves like <c:set> without a scope. This is not the intented usage.
Just use <c:set> without a scope if it's absolutely necessary to "alias" a (long) EL expression.
<c:set var="id" value="#{user.id}" />
Put it outside the <h:commandLink> though. Also in this construct, it's kind of weird. It doesn't make the code better. I'd just leave out it.
<f:setPropertyActionListener ... value="#{user.id}" />
See also:
Setting ui:param conditionally
what is the scope of <ui:param> in JSF?
Defining and reusing an EL variable in JSF page
Unrelated to the concrete problem, if you're using EL 2.2 (as you're using JSF 2.2, you undoubtedly are as it requires a minimum of Servlet 3.0, which goes hand in hand with EL 2.2), then just pass it as bean action method argument without <f:setPropertyActionListener> mess. See also a.o. Invoke direct methods or methods with arguments / variables / parameters in EL and How can I pass selected row to commandLink inside dataTable?
<h:commandButton ... action="#{userService.toUserInfo(user.id)}">
On again another unrelated note, such a "View user" or "Edit user" request is usually idempotent. You'd better use <h:link> (yes, with <f:param>) for this. See also a.o. Creating master-detail pages for entities, how to link them and which bean scope to choose and How to navigate in JSF? How to make URL reflect current page (and not previous one).
Oh, that <h:panelGrid> around the <ui:repeat><li> doesn't make sense in HTML perspective. Get rid of it and use <ul> instead. See also HTMLDog HTML Beginner tutorial.

How to invoke a managed bean action method in on* attribute of a JSF component

I'd like to invoke a managed bean action method in an on* attribute. In my particular case I need to logout an user if the user is idle for 3 minutes as below:
<p:idleMonitor onidle="#{mybean.processTimeOut()}" timeout="180000" />
However, the managed bean action method is immediately invoked as the page loads. How is this caused and how can I solve it?
Like as all other on* attributes on all JSF components, the onidle attribute must represent a JavaScript callback, not a JSF backing bean action method. Any EL expressions in on* attributes would be evaluated immediately as String value expressions during generating the HTML output in expectation that they print (part of) JavaScript code.
It's exactly like as if you're doing <h:outputText value="#{mybean.processTimeout()}">. If you had removed the parentheses (), you'd have faced a PropertyNotFoundException which was also a hint at its own of it being evaluated as a value expression instead of a method expression.
In order to invoke a JSF backing bean method using JavaScript, you need an additional <p:remoteCommand>.
<p:idleMonitor onidle="processTimeout()" timeout="180000" />
<p:remoteCommand name="processTimeout" action="#{mybean.processTimeOut}" />
If you're not on PrimeFaces, head to the alternatives posted in this related answer: How to invoke a JSF managed bean on a HTML DOM event using native JavaScript?

EL expression in c:set gets called multiple times instead of its return value being used

I have an Action in request scope. The return value of one of its methods is passed around to a custom facelet tag. This tag then extracts several attributes of the returned object and displays them. The problem is the EL expression which has the method call on the Action is called for every evaluation of the attribute of the returned object. I will put the relevent pieces of code here.
some.xhtml
<ui:include src="someOther.xhtml">
<ui:param name="profileUri" value="#{param['relateToProfile']}"/>
<ui:param name="qualifier" value="#{param['qualifier']}"/>
<ui:param name="cellStyleClass" value="#{param['cellStyle']}"/>
</ui:include>
someOther.xhtml (approach 1) Note that ProfileAction is in #RequestScoped
<tenui:entityCard profileEntity="#{profileAction.getProfileMetadata(profileUri)}"
qualifier="#{qualifier}"
cellStyleClass="#{cellStyleClass}"/>
enityCard.xhtml(facelet custom tag)
<ui:fragment rendered="#{profileEntity.featured}">...
<tenui:gridCell id="#{profileEntity.profileId}#{qualifier}" ...
<tenui:metaunit ..content="#{profileEntity.getMeta('memberName')}"
href="/#{profileEntity.profileDisplayUri}"
hrefStyleClass="a-styled grid-cell-name"/>
.....
...several other EL expressions including #{profileEntity.xxx}
The problem is #{profileAction.getProfileMetadata(profileUri)} is being called for every attribute evaluation in entityCard.xhtml Then, I thought I would save the return value of method call in a c:set var(approach 2 as noted below) but it doesn't help.
someOther.xhtml (approach 2)
<c:set var="profileMetadata"
value="#{profileAction.getProfileMetadata(profileUri)}"/>
<tenui:entityCard profileEntity="#{profielMetadata}"
qualifier="#{qualifier}"
cellStyleClass="#{cellStyleClass}"/>
The action method calls a Stored proc which is quite expensive and the returned object has over 20 attributes that get evaluated in ELs in entityCard.xhtml.
I also tried another approach with resolving teh value at ui:param itself by calling the action method directly, but of no avail at all. The problem remained.
Can someone point to what could I be doing wrong? Or, how I could avoid the multiple calls to profileAction.getProfileMetadata call?
You need to set the scope attribute of <c:set> to one of the desired scopes, request, view, session or application. Otherwise it defaults to none.
Assuming that you want it to be request, this should do:
<c:set var="profileMetadata" scope="request"
value="#{profileAction.getProfileMetadata(profileUri)}" />

UIComponent#getValue() obtained via binding is not available in validator of another component

I'm trying to figure out why an f:attribute tag's value isn't passed when attached to h:inputSecret tag. I'm quite new to jsf, but as far as I know attributes can be attached to any kind of component. Here is the code:
<h:inputSecret id="passw" value="#{advertAdder.userPass}"
required="true" validator="#{advertAdder.validatePasswords}">
<f:attribute name="confirmedPass" value="#{advertAdder.passConfirmator.value}"/>
</h:inputSecret>
<h:inputSecret id="passwConfirm" required="true"
binding="#{advertAdder.passConfirmator}"/>
and the method that wants to acces this attribute:
public void validatePasswords(FacesContext context, UIComponent component, Object value)
{
if (!value.equals(component.getAttributes().get("confirmedPass")))
{
FacesMessage mess = new FacesMessage("Password and it's confirmation are not the same!");
context.addMessage(component.getClientId(context), mess);
((UIInput) component).setValid(false);
}
}
In above code component.getAttributes() always returns map with only two attributes:
javax.faces.component.VIEW_LOCATION_KEY and com.sun.faces.facelets.MARK_ID.
I've added attribute tag to a h:commandButton to check it, and then everything was fine. Am I missing something or it's not possible to add an attribute to non-action tag?
I'm using Mojarra 2.0.2 and Glassfish 3.0.1.
Thanks in advance.
Input components are processed in the order as they appear in the component tree. The UIInput#getValue() is only available when the component is already been processed. Otherwise you need to use UIInput#getSubmittedValue() instead.
<f:attribute name="confirmedPass" value="#{advertAdder.passConfirmator.submittedValue}"/>
Note that this gives you the unconverted and unvalidated value back. It would make somewhat more sense to put the validator on the confirm password field instead and pass the value of the first password field along. See also JSF Validator compare to Strings for Equality and JSF doesn't support cross-field validation, is there a workaround?
Alternatively, you can also try out the OmniFaces <o:validateEqual> component. You can find a concrete example in this article.
Unrelated to the concrete problem, it's unnecessary to bind the component to the bean this way. Replace all occurrences of #{advertAdder.passConfirmator} by #{passConfirmator}. Keep the controller free of properties which are never internally used.

Resources