How does exactly the following code work:
#{aaa.id}
<h:inputText id="txt1" binding="#{aaa}"/>
I mean, usually the component binding works, by specifying a property (of type UIComponent) in a bean. Here, there's no bean nor property but nevertheless the name "aaa" gets bound correctly (displaying the component id - "txt1"). How does it work/where is it specified?
Thanks
UPDATE: The JSF2.0 Spec [pdf] (Chapter 3.1.5) says:
"A component binding is a special value expression that can be used to facilitate “wiring up” a component instance to a
corresponding property of a JavaBean... The specified ValueExpression must point to a read-write JavaBeans property of type UIComponent (or
appropriate subclass)."
It's been put in the default EL scope during building of the view tree (that's when all binding attributes -- and attributes of tag handlers like JSTL <c:xxx> and JSF <f:xxx> -- are being evaluated). It's being shown by normal EL means during rendering of the view tree. Rendering of the view tree happens after building of the view tree, so it works that way. It's not that this code runs "line by line" as you seemed to expect from the source.
I can't point you out a single reference where it's been specified as there is none. You'd have to read both the EL spec and JSF spec separately and do a 1+1=2.
By the way, to avoid confusion among new developers and to avoid clashes with existing variables in the EL scopes, you can use a java.util.HashMap in the request scope which is been declared as follows in faces-config.xml:
<managed-bean>
<description>Holder of all component bindings.</description>
<managed-bean-name>components</managed-bean-name>
<managed-bean-class>java.util.HashMap</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
and is been used as follows
#{components.aaa.id}
<h:inputText id="txt1" binding="#{components.aaa}"/>
which is more self-documenting.
See also:
How does the 'binding' attribute work in JSF? When and how should it be used?
Related
Hi We have recently upgraded Struts2 from Struts 2.5.22 to 2.5.27 . In our application we are are using Struts Jquery Grid. We are using struts2-jquery-grid-plugin-4.0.3.jar library.
One of our application need is to assign grid id a dynamic value which is bean property.
My code snippet is below:
<sjg:grid id="%{#tabGrid.gridId}" caption="%{#tabGrid.gridCaption}" gridModel="%#tabGrid.gridData}" href="%{gridUrl}"-------->
Before upgrade above piece of code was working. But after the upgarde we are unable to assign grid id bean property.But we can assign grid caption bean property like shown in above code snippet.Only when we are assigning id a bean property my code is breaking.
I have tried to workaround by assigning grid class value of property bean than id. But this change will impact lot of code changes in my application.
Please suggest what could be the reason for it and possible solution.
Since Struts 2.5.26 you no longer can use %{} to force OGNL evaluation in the Struts tags using public attributes which leads to double evaluation of OGNL expression. This fixture is documented in S2-061.
Some of the tag's attributes could perform a double evaluation if a developer applied forced OGNL evaluation by using the %{...} syntax. Using forced OGNL evaluation on untrusted user input can lead to a Remote Code Execution and security degradation.
I was reading some code and I found the next EL expression inside a JSF file:
${text['somefield']}
How is it work?.
Since I don't have access to the whole code, I can check what it is. Is it "text" a managed bean?.
Because I could understand the next code:
${someBean.text['somefield']}
(accessing a field array inside a bean but it's not the case.
text can be a managed bean, a CDI dependency (these are the 2 most likely)
text['somefield'] is reading somefield field of text object. text is likely to be a map, but it could be a normal bean too. It's equivalent to text.somefield
In the documentation, you can also find similar exampes:
${customer.address["street"]}
Which is similar to:
${customer.address.street}
I have one property file linked both ways (using f:loadBundle and faces-config.xml) both with different var names. So it would look like the following:
datatypes.properties:
A=first
B=second
C=third
faces-config.xml:
<resource-bundle>
<base-name>datatypes</base-name>
<var>myProp</var>
</resource-bundle>
myPage.xhtml:
<f:loadBundle basename="datatypes" var="prop"/>
in myPage.xhtml I make a list of all the keys from the property file. What I can't seem to understand is that when I use #{prop} in the code below it works but when I replace it with #{myProp} the list no longer displays.
<h:form>
<h:selectManyListbox id="list">
<f:selectItems value="#{myProp}"></f:selectItems>
</h:selectManyListbox>
</h:form>
I figure this means the variables in both cases are not the same behind the scenes but I would appreciate it if someone could explain (or point me to an explaination) in what way they are different. I would ideally like to just use #{myProp} without having to pull the keys out in code and store them in a list.
Thanks.
Both <f:loadBundle> and <resource-bundle> are different ways to load properties with difference being in their access scopes. The latter has by the way the additional benefit that the bundle is also injectable in a managed bean by #ManagedProperty("#{myProp}")
Using <resource-bundle> in faces-config.xml creates a global resource bundle which can be accessed anywhere in your application. This is implemented through a java.util.ResourceBundle instance.
Using <f:loadBundle> in your view creates a view-specific resource bundle which is accessible only within that view. The tag handler implements this using an internal implementation of a Map. This is as specified in the VDL of the tag:
Load a resource bundle localized for the Locale of the current view,
and expose it as a java.util.Map in the request attributes of the
current request under the key specified by the value of the "var"
attribute of this tag.
Now since you're trying to use the values from datatypes.properties through <f:selectItems>, you'll get the said exception. This is because the value attribute for the tag should evaluate to a Collection or an array.
Value expression pointing at any Collection or array. The member
elements may be instances of SelectItem or any Java Object.
So in order to use the global bundle instance, you first have to convert the same into a List<SelectItem> inside your backing bean before using it.
NOTE: You can verify the above cases by setting a breakpoint in the initializeItems(Object) method in the com.sun.faces.renderkit.SelectItemsIterator class. This is, of course, assuming that you're using the Mojarra implementation.
I use a managed bean to generate an HtmlPanelGrid, and then bind it in the xhtml file, like so
<h:panelGrid id ="questions" binding="#{ui.generatedComponents}" />
On this page is a form, with a dropdown, and whenever a value is selected, it shows the page. However, whe something is selected, every other (static i.e in xhtml page) component is shown, but the binded component is never shown.
However, if I re-request the page in the browser, it does show them.
Mucho confusing. Any ideas?
When using binding, you need to make absolutely sure that the property behind this attribute is exclusively been used by this component in the current view. The managed bean should not be in the session scope, because it would then share the same property between multiple views (browser windows/tabs) in the same session. It should of course also not be in the application scope. The managed bean should be at highest in request or view scope. The view scope makes the most sense for this particular purpose.
The getter method of the property behind binding should also contain no business code. It should solely return the property, nothing more. Any initialization needs to be done in the (post)constructor or an (action)listener method of the backing bean class. Any manipulation of this component property needs to be done in an (action)listener method of the backing bean class.
Not doing so may result in awkward behaviour.
I have the following line in a JSF page:
<h:commandLink action="#{myBean.test}" value="Wizard Step"></h:commandLink>
I expect that when the page is loaded, the Bean corresponding to myBean will be instantiated (and I'll be able to see this in the eclipse debugger).
The rest of the JSF is working correctly, but this bean is not resolving (without any error).
How do I get the errors from the el failing to resolve the bean?
If there are EL errors, you will surely get an exception of javax.el package:
ELException: Represents any of the exception conditions that can arise during expression evaluation.
MethodNotFoundException: Thrown when a method could not be found while evaluating a MethodExpression.
PropertyNotFoundException: Thrown when a property could not be found while evaluating a ValueExpression or MethodExpression.
PropertyNotWritableException: Thrown when a property could not be written to while setting the value on a ValueExpression.
In your case, the managed bean is not constructed on initial request. This can only mean that the managed bean is not referenced elsewhere in the view. The EL in action attribute is only evaluated when the form is submitted. So the bean will only be constructed when the action is invoked. As a test, just put #{myBean} somewhere in the view. You'll see that it get constructed on initial request.
Your real problem is that command button action is simply not invoked, so the EL in its action attribute is simply not evaluated at all. The problem cannot be debugged nor nailed down in the EL side. There are a lot of possible causes for the button action not being invoked. You can find them all here: commandButton/commandLink/ajax action/listener method not invoked or input value not updated. The most common cause among starters is that the button is inside an repeating component like <h:dataTable> whose value is not properly preserved and returns a completely different value during the form submit request, or that the component or one of its components has a rendered attribute which is not properly preserved and defaults to false.