How to get a JSF resource bundle property value in backing bean? - jsf

I am using JSF 2. I am trying to resolve a message bundle reference dynamically the a managed bean property. The value contains the bundle name as well as the key. This is required as the value may come from one of a few different bundles. I have tried many permutations, but the value from the bean seems to be always resolved as a literal String (outputting with EL brackets) and the bundle is never called to resolve and return the value. Any ideas?
I have tried:
#{bundle['key']}
${bundle['key']}
bundle['key']
They are outputted exactly as-is, also in a <h:outputText>. It works fine if I write it directly in the page. My theory is that JSF doesnt realise it has to process the String as an expression. Is there some way to force it?

EL will only be resolved in the view, not in the model. It would otherwise be a huge EL injection attack hole which allows endusers to enter arbitrary EL expressions in input fields and have them resolved. No, you cannot force it in any way.
You need to resolve it yourself. You can do that by either evaluating it programmatically using Application#evaluateExpressionGet():
FacesContext context = FacesContext.getCurrentInstance();
String value = context.getApplication().evaluateExpressionGet(context, "#{bundle['key']}", String.class);
// ...
Or, in this particular case, by just using the ResourceBundle API directly like as JSF is doing under the covers:
ResourceBundle bundle = ResourceBundle.getBundle(basename, FacesContext.getCurrentInstance().getViewRoot().getLocale());
String value = bundle.getString("key");
// ...

Try this..
Resource Bundle referenced by msg
USD=$
xhtml code:
<c:set var="key" value="#{managedBean.currencyCode}" />
<h:outputText value="#{msg[key]}"/>
This should work..

Related

How to obtain submitted value from a custom JSF input component? [duplicate]

I have created a custom component. I add a dynamic input text box to it (from the encode function).
The component is correctly is rendered as HTML.
But I want to bind the value of the text box to some property on the Managed Bean. So some other developer can use the component on his jsp with his managed bean.
I want to know, what should I do, so that the value entered in the text box (which my component dynamically creates) is set to the some Managed bean property.
You need to ensure that your custom component class extends UIInput and that you're in the encodeEnd() method of your renderer writing the component's client ID as name attribute of the HTML input element. Then you can in the overriden decode() method of your renderer just grab the submitted value from the request parameter map with the component's client ID as parameter name and set it as UIInput#setSubmittedValue() and let JSF do the remnant of the job of converting, validating and updating the model value.
#Override
public void decode(FacesContext context, UIComponent component) {
// Do if necessary first validation on disabled="true" or readonly="true", if any.
// Then just get the submitted value by client ID as name.
String clientId = component.getClientId(context);
String submittedValue = context.getExternalContext().getRequestParameterMap().get(clientId);
((UIInput) component).setSubmittedValue(submittedValue);
}
Unrelated to the concrete problem, are you aware of the new composite component support in JSP's successor Facelets? I have the impression that you don't necessarily need a custom component for this purpose. Or are you really restricted to using the legacy JSP as view technology in spite of that you're already on JSF 2.x? See also When to use <ui:include>, tag files, composite components and/or custom components?
Well, the problem is solved.
In the encodeEnd() method I added the element as
HtmlInputHidden hidden = new HtmlInputHidden();
hidden.setParent(this);
hidden.setId("someId");
ValueExpression ve = getValueExpression("value");
hidden.setValueExpression("value", ve);
hidden.encodeBegin(context);
hidden.encodeEnd(context);
This seems to have some problem.
Then I changed this to ...
HtmlInputHidden hidden = new HtmlInputHidden();
hidden.setId("someId");
ValueExpression ve = getValueExpression("value");
hidden.setValueExpression("value", ve);
this.getChildren().add(hidden);
hidden.encodeBegin(context);
hidden.encodeEnd(context);
The use of this.getChildren().add(); solved my problem
P.S. Obviously before adding the element, it needs to be checked if the element is already present.

EL variable resolution in JSF: is there a way to control when it happens?

I often face the following problem. I have a JSF application and a facelet where I write EL expressions, like this:
<h:outputText value="#{myBean.foo}">
As long as myBean, as a variable, has a life long enough, there's no problem to evaluate myBean.foo at any given time, but if myBean is a variable that references some bean within a short period of time, when myBean.foo is evaluated it might be too late, so that JSF complains that myBean resolves to null. This is something well-known, but the problem is that it is not clear to me what to expect in different situations.
Concrete example n. 1: if you try the following with PrimeFaces OrderList:
<p:orderList value="#{bean.myValue}" var="item">
<p:column>
<p:commandLink action="#{bean.doSomething(item)}" />
</p:column>
</p:orderList>`
This is not going to work, because when doSomething is called, the item variable is no longer defined (although the object it references is still alive) and hence it's resolved to null. It's a known issue. However the same pattern works fine with <p:dataTable>, for instance. Anyway, I'm not interested right now in this specific problem, I just want to explain my doubt.
Concrete example n. 2: I have written a composite component with a backing bean. The backing bean extends UINamingContainer and uses its StateHelper to retain a model object. This composite allows to write child tags and I would like to write something like this:
<myns:myCc var="myVar">
<h:inputText value="#{myVar.foo}" />
</myns>
With "myVar" I want to give a name to the model object. To make this work, I tried to store the model object in the request map at the beginning of encodeChildren method and remove it afterwards: this works for rendering, but if I then process the input with a commandButton action, it does not work because when the action gets executed it says that myVar can't be resolved: in other words, it tries to resolve the entire expression too late. I then tried to "permanently" save the model object in the view scope map, but it doens't work either. However, if I change this to:
(assuming modelObject is the property field in the backing bean that stores my model object)
it works. So, it is not a problem in my model, but in the way I try to make the model object available to EL expressions for child tags.
Concrete example n. 3: I often use the <ui:param> tag to give beans a shorter name and to ease templating. For instance:
<ui:param name="bean" value="#{longNamedAndPageSpecificBean}" />
So that, in the remainder of the page I can just use #{bean.foo} instead of #{longNamedAndPageSpecificBean.foo}. This works fine even for actions passed to command buttons. However, if I pass a method expression like #{bean.myActionMethod} to a composite component attribute declared with method-signature, when this method expression is actually invoked I receive an error that bean resolves to null... The reason why it works in one case (with commandButton actions) and not in the other (with actions used by the composite component) is a big source of confusion for me.
I would appreciate if someone can help me to understand better this JSF aspect and suggest better approaches/workarounds with the aforementioned concrete examples.
Your question looks too large, but i could say that, during the build time only Session and request scoped values are avaiaible.
The same thing is true for the Execution phase.
Only the render phase should ensure the avaibility of temporal vars "myVar".
The best way to understand what its realy hapening is to debug because its depends on the component implementation

h:outputtext issue in passing attributes

I have a search screen where I search for a customer id and it consumes a webservice a returns list of objects. I display the results in a datatable.For a specific field , I have a method which provides the value based on a key value in each row of the list being iterated. The key value is productID. I set that in a bean named output. In the getCustomerValue method I call the method which provides the relevant value by passing the value of "productID". I use the below listed code to do the same.
<h:outputText id="customerID" binding="#{myBean.output}" value="#{customerBean.customervalue}">
<f:attribute name="myID" value="#{item2.customerService.productID}"/>
</h:outputText>
The value gets displayed properly when the page is loaded. I have hyperlink in the same page which basically calls the same webservice and renders the same page.But this time around all the values except the value listed above is being displayed. When I print the value of attribute "item2.customerService.productID" in the method "customervalue" , it is displayed as null.I am not sure why this value isn't being passed.
You're displaying this in a <h:dataTable>. The <f:attribute> is specific to the component itself, not to its generated HTML output. The <f:attribute> is evaluated during view build time, not during the view render time. At the moment JSF builds the view, the #{item2} is not present in the scope. It's only present in the scope when JSF renders the view.
You need to look for the solution by alternate means. It's unclear what JSF version you're using, but based on your question you're using JSF 1.2 (in the future questions, please explicitly mention the JSF impl/version you're using; in JSF 2.0 a lot of things can be done differently and much more elegantly).
My answer on your previous question of Passing parameters to a method in h:outputtext tag should be the best answer to your current problem. This is apparently not an option somehow. In that case, there are at least 3 alternative ways:
Move the property to the class behind #{item2}:
<h:outputText value="#{item2.customervalue}">
You've in there instant access to the customerservice property.
Get the current item inside the getter by evaluating EL programmatically:
public String getCustomervalue() {
FacesContext context = FacesContext.getCurrentInstance();
Long productID = context.getApplication().evaluateExpressionGet(context, "#{item2.customerService.productID}", Long.class);
// ...
}
(I assume that productID is a Long)
Bind the datatable's value to a DataModel:
private DataModel<Item2> items;
with
<h:dataTable value="#{customerBean.items}" var="item2">
and
public String getCustomervalue() {
Item2 item2 = items.getRowData();
// ...
}

What is the correct way to bind input value to JSF managed bean property?

I am new to JSF and managed beans. I have a managed bean with some private property with public setter and Getter methods. Now when I add the managed bean's properties to JSF forms, should I add the private methods directly or should I use call the property by Getter methods?
For example:
<h:inputText value="#{BeanName.userName}"/>
<h:inputText value="#{BeanName.getUserName()}"/>
Which one is correct in above?
Assuming that you're using JBoss EL or EL 2.2+, both ways would work fine in the initial display. But the first one is actually more correct because the second one would only get the value, but never set the value. If you want to collect input values, you should always go for the first way. The EL (Expression Language) will then automatically locate the getUserName() and setUserName() methods whenever needed.
The second way will never work when you're using standard JSF EL implementation since it doesn't support direct method calls.
To learn more about JSF, start at our JSF wiki page.
If in your java class you have something like
....
private String coolStuff;
public String getCoolStuff() {
return coolStuff;
}
....
Then in your jsf page you access it like so:
#{myBackingBean.coolStuff}
The framework automatically looks for a method called getCoolStuff()
Hope that helps
number 1 is correct from above it is the private field that you connect if you are using EL with JSF in your form.
You still need the getter and the setter which the managed bean calls to get the values so you can save them in a database ....etc

JSF validation error, lost value

I have a update form, with composite keys All composite keys are displayed in outputbox as I have hidden field for each composite keys. These outputbox values are empty after validation error. How do I resolve this. I am on the same page so doesn't it has to have the values.
This is indeed a non-intuitive behaviour of the h:inputHidden (I've ever filed a issue against it at the Mojarra issue list, but they didn't seem to do anything with it). The whole problem is that the component's value unnecessarily is also taken into the entire validation cycle while there's no means of user-controlled input. It will get lost when the validation fails. There are at least three ways to fix this non-intuitive behaviour.
First way is to use the binding on the h:inputHidden instead:
<h:inputHidden binding="#{bean.hidden}" />
This way the value won't undergo the unnecessary validation cycle. This however requires changes in the way you get/set the values in the backing bean code. For example:
private HtmlInputHidden hidden = new HtmlInputHidden(); // +getter +setter.
public void setHiddenValue(Object hiddenValue) {
hidden.setValue(hiddenValue);
}
public Object getHiddenValue() {
return hidden.getValue();
}
Second (and IMHO the preferred way) is to use Tomahawk's t:saveState instead.
<t:saveState value="#{bean.property}" />
The major advantage is that you don't need to change anything in the backing bean code. It will restore the value early before the apply request values phase. You only need to add extra libraries if not done yet, but as Tomahawk provides much more advantages than only the t:saveState, such as the in basic JSF implementation missing components/features t:inputFileUpload, t:dataList, t:dataTable preserveDataModel="true", t:selectOneRadio layout="spread" and so on, it is worth the effort.
The third way is to store it in a session scoped bean, but you actually don't want to do that for request scoped variables. It would only give "wtf?" experiences when the enduser has multiple tabs/windows open in the same session.

Resources