JSF composite:attribute with f:attribute conversion error - jsf

I'm implementing a JSF component and need to conditionally add some attributes. This question is similar to a previous JSF: p:dataTable with f:attribute results in "argument type mismatch" error, but with a completely different error message, so I raised a new question.
<composite:interface>
<composite:attribute name="filter" required="false" default="false"
type="java.lang.Boolean"/>
<composite:attribute name="rows" required="false" default="15"
type="java.lang.Integer"/>
...
</composite:interface>
<composite:implementation>
<p:dataTable ivar="p" value="#{cc.attrs.dm}">
<c:if test="#{cc.attrs.filter}">
<f:attribute name="paginator" value="#{true}"/>
<f:attribute name="rows" value="#{cc.attrs.rows}"/>
</c:if>
...
<p:dataTable>
</composite:implementation>
This results in an error java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer. Even if I manually set this, I get errors:
<f:attribute name="rows" value="15"/> ... argument type mismatch
<f:attribute name="rows" value="#{15}"/> ... java.lang.Long cannot be cast
to java.lang.Integer
If I add the attribute directly, there is no exception and the correct number of rows is diplayed:
<p:dataTable var="p" value="#{cc.attrs.dm}" rows="#{cc.attrs.rows}">

This is indeed an unfortunate corner case with numbers in EL and composite component attributes. There's no solution for this. The type information is not available in #{cc.attrs} when used in <f:attribute> and thus treated as String. The #{15} cannot be represented as an integer in EL either, all numbers are always implicitly treated as Long when the type information is absent. The ClassCastException can be prevented by using a tag file instead of a composite component.
Your best bet is doing the check in the actual rows attribute itself.
<p:dataTable ... rows="#{cc.attrs.filter ? cc.attrs.rows : null}">

Related

How to Validate number field from <f:validateRegex>? [duplicate]

In a managed bean I have a property of the type int.
#ManagedBean
#SessionScoped
public class Nacharbeit implements Serializable {
private int number;
In the JSF page I try to validate this property for 6 digits numeric input only
<h:inputText id="number"
label="Auftragsnummer"
value="#{myController.nacharbeit.number}"
required="true">
<f:validateRegex pattern="(^[1-9]{6}$)" />
</h:inputText>
On runtime I get an exception:
javax.servlet.ServletException: java.lang.Integer cannot be cast to java.lang.String
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Is the regex wrong? Or are the ValidateRegex only for Strings?
The <f:validateRegex> is intented to be used on String properties only. But you've there an int property for which JSF would already convert the submitted String value to Integer before validation. This explains the exception you're seeing.
But as you're already using an int property, you would already get a conversion error when you enter non-digits. The conversion error message is by the way configureable by converterMessage attribute. So you don't need to use regex at all.
As to the concrete functional requirement, you seem to want to validate the min/max length. For that you should be using <f:validateLength> instead. Use this in combination with the maxlength attribute so that the enduser won't be able to enter more than 6 characters anyway.
<h:inputText value="#{bean.number}" maxlength="6">
<f:validateLength minimum="6" maximum="6" />
</h:inputText>
You can configure the validation error message by the validatorMessage by the way. So, all with all it could look like this:
<h:inputText value="#{bean.number}" maxlength="6"
converterMessage="Please enter digits only."
validatorMessage="Please enter 6 digits.">
<f:validateLength minimum="6" maximum="6" />
</h:inputText>
You can achieve this without regex also
To validate int values:
<h:form id="user-form">
<h:outputLabel for="name">Provide Amount to Withdraw </h:outputLabel><br/>
<h:inputText id="age" value="#{user.amount}" validatorMessage="You can Withdraw only between $100 and $5000">
<f:validateLongRange minimum="100" maximum="5000" />
</h:inputText><br/>
<h:commandButton value="OK" action="response.xhtml"></h:commandButton>
</h:form>
To validate float values:
<h:form id="user-form">
<h:outputLabel for="amount">Enter Amount </h:outputLabel>
<h:inputText id="name-id" value="#{user.amount}" validatorMessage="Please enter amount between 1000.50 and 5000.99">
<f:validateDoubleRange minimum="1000.50" maximum="5000.99"/>
</h:inputText><br/><br/>
<h:commandButton value="Submit" action="response.xhtml"></h:commandButton>
</h:form>

jsf make ui:param result static

I am using templating and pass some values by to use them in the template:
<ui:repeat var="entry" value="#{showEntriesBean.entries}" id="repeatId">
<ui:include src="/templates/entryTemplate.xhtml">
<ui:param name="prePath" value="/" />
<ui:param name="allowedToSee" value="#{bean.calcRandom(0, 10)}" />
</ui:include>
<br />
</ui:repeat>
I found out, that everytime I use the "allowedToSee" variable in my entryTemplate.xhtml, it recalculates its value.
Is there any way to pass the result of calcRandom in a static way? So it is ONCE calculated (when the allowedToSee value is calculated) and performs like a final number? I don't want it to be calculated everytime #{allowedToSee} is used
If you want the value to be held, you should held it somewhere.
What I would do:
1) Create a List<Integer> property.
2) When the values of the entries properties are set, call a method (preRenderEvent? #PostConstruct?) that introduces in your list as many items as there are in entries.
3) Consult that list using the varStatus attribute of ui:repeat
Little more of less, like:
<ui:repeat var="entry" value="#{showEntriesBean.entries}" id="repeatId" varStatus="status">
<ui:include src="/templates/entryTemplate.xhtml">
<ui:param name="prePath" value="/" />
<ui:param name="allowedToSee" value="#{bean.getPrecalculedRandomAt(status.index)}" />
</ui:include>
<br />
</ui:repeat>
More on the varStatus attribute: http://docs.oracle.com/javaee/6/javaserverfaces/2.0/docs/pdldocs/facelets/ui/repeat.html

Dynamically build the column values

I am building a component that will build a data table dynamically. I need to pass in the field name from the class and concatenate it to the var attribute of the table. example : "tblVar.firstName". I have tried this using a ui:param as the below code shows, but it just prints the string expression it doesn't evaluate the firstName.
Is there a way to take a string and turn it into an EL expression.
<composite:interface>
<composite:attribute name="pageBean" type="pagecode.app.Maintenence" required="true"/>
<composite:attribute name="dataTableList"/>
<composite:attribute name="columnHeader"/>
<composite:attribute name="columnFieldName"/>
</composite:interface>
<composite:implementation>
<p:dataTable id="doc_code_table" value="#{cc.attrs.pageBean.documentCodeList}"
var="tblVar" rowIndexVar="index" paginator="false">
<ui:param value="#{tblVar}.#{cc.attrs.columnFieldName}" name="colValue"/>
<p:column headerText="#{cc.attrs.columnHeader}">
<h:outputText value="#{colValue}"/>
</p:column>
</p:dataTable>
</composite:implementation>
You're there indeed creating a string variable. The effect is exactly the same as when you do this:
<h:outputText value="#{tblVar}.#{cc.attrs.columnFieldName}" />
This is not right. You should use the brace notation #{bean[property}} to use a variable as property name. Thus, so:
<h:outputText value="#{tblVar[cc.attrs.columnFieldName]}"/>
See also:
Our EL wiki page

JSF Compound EL expression

I am trying to validate a inputText box based on the selection of a CheckBox as shown below.
< <h:inputText required="#{param[facesContext.externalContext.response.namespace'form:checkBoxId']}"> >.
The issue is as you see, the component Ids are dynamic, I should be able to use facesContext.externalContext.response.namespace inside the EL expression. Is there a solution to it, appreciate any suggestions.
Thanks.
Just bind the UIComponent to a page scoped property and access its getValue() method.
<h:selectBooleanCheckbox binding="#{checkbox}" />
<h:inputText required="#{not empty checkbox.value and checkbox.value}" />
As to the dynamicness, you can also go around by just giving it a fixed id.
<h:form id="form">
<h:selectBooleanCheckbox id="checkbox" />
<h:inputText required="#{not empty param['form:checkbox'] and param['form:checkbox']}" />
</h:form>
It's however only ugly when it gets lengthy.

Dynamically changing the visibility of the JSF components

My requirement is like this: I am having a text input and whenever a value change event occurs, a select many list box has to be populated. If there is no matching records found, then a text input has to appear instead of a select many list box.
<h:column>
<h:selectManyListbox size="3" value="#{hostInfoBean.gateKeeperendPointReference}" rendered="#{hostInfoBean.selectManyRendered}" id="gateKeeperendPointReference">
<f:selectItems value="#{hostInfoBean.gateKeeperendPointReferenceItems}" />
</h:selectManyListbox>
<h:inputText id="gateKeeperendPointReferenceText" size="30" rendered="#{!hostInfoBean.selectManyRendered}">
</h:inputText>
</h:column>
Also I am using a4j for the value change listener,
<a4j:support event="onchange" reRender="hostInfo:gateKeeperendPointReference" focus="GFacPath"
ajaxSingle="true" />
'selectManyRendered' is a boolean value which I am determining in the JAVA bean. The program works only for the default value of the boolean variable. If the boolean value is changed during runtime, then the toggle between the visibility of selectManyListbox and inputText is not working. Please help to fix this. Am i missing something?
regards,
Suresh
If the "rendered" attribute resolves to false, then the component isn't in your tree and can't be found as a "rerender" target. When you have components that are rendered conditionally you want to wrap them in a component that is always available as a target, like so:
<h:inputText value="#{myBean.text}" >
<a4j:support event="onkeyup" reRender="listZone" ajaxSingle="true" />
</h:inputText>
<h:panelGroup id="listZone">
<h:selectManyListbox value="#{myBean.list}" rendered="#{myBean.renderList}" >
<f:selectItems value="#{myBean.listItems}" />
</h:selectManyListbox>
<h:inputText size="30" rendered="#{!myBean.renderList}/>
<h:panelGroup id="listZone">

Resources