JSF Conversion of a LocalDate keep getting me Exceptions - jsf

I have an xhtml page where you can enter your name, your birthdate, aswell as your gender.
My task is to convert the incoming String as a LocalDate to use it in a (JSF) validator to check if the person is over 18. The String that I want to convert is alrady in the correct format (eg. 01.01.2022), but as soon as my dateTimeFormatter should convert the String into a LocalDate the format changes an Exception is being thrown. I don't geht why the conversion isn't working and why the Log says somethin about a DateTimeConverter.
This is my Validator:
<h:body>
<h:form id="inputForm">
<h:outputText id="birthdateOutput" value="Birthdate:: " />
<h:inputText id="birthdate" value="#{form.birthdate}" rquired="true">
<f:converter converterId="dateConverter" />
<f:validator validatorId="ageValidator" />
</h:inputText>
<br />
</h:form>
</ui:define>
This is my Converter:
#FacesConverter(value = "dateConverter")
public class DateConverter implements Converter<LocalDate> {
#Override
public String getAsString(FacesContext context, UIComponent component, LocalDate value) {
return value.toString();
}
#Override
public LocalDate getAsObject(FacesContext context, UIComponent component, String value) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
LocalDate returnDate = LocalDate.parse(value, dateTimeFormatter);
return returnDate;
}
}
Thats my Error-Log:
javax.servlet.ServletException: j_idt8:j_idt10: Could not convert '2022-01-10' to a string.
at javax.faces.api#3.0.0.SP04//javax.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:725)
at javax.faces.api#3.0.0.SP04//javax.faces.webapp.FacesServlet.service(FacesServlet.java:451)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
at io.opentracing.contrib.opentracing-jaxrs2//io.opentracing.contrib.jaxrs2.server.SpanFinishingFilter.doFilter(SpanFinishingFilter.java:52)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at org.wildfly.extension.undertow#24.0.1.Final//org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.core#2.2.8.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:117)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.core#2.2.8.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.core#2.2.8.Final//io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.core#2.2.8.Final//io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
at io.undertow.core#2.2.8.Final//io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
at io.undertow.core#2.2.8.Final//io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
at io.undertow.core#2.2.8.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow#24.0.1.Final//org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.core#2.2.8.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow#24.0.1.Final//org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.handlers.SendErrorPageHandler.handleRequest(SendErrorPageHandler.java:52)
at io.undertow.core#2.2.8.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:78)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:133)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at org.wildfly.extension.undertow#24.0.1.Final//org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
at org.wildfly.extension.undertow#24.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1535)
at org.wildfly.extension.undertow#24.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1535)
at org.wildfly.extension.undertow#24.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1535)
at org.wildfly.extension.undertow#24.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1535)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:78)
at io.undertow.servlet#2.2.8.Final//io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99)
at io.undertow.core#2.2.8.Final//io.undertow.server.Connectors.executeRootHandler(Connectors.java:387)
at io.undertow.core#2.2.8.Final//io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:841)
at org.jboss.threads#2.4.0.Final//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads#2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1990)
at org.jboss.threads#2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
at org.jboss.threads#2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
at org.jboss.xnio#3.8.4.Final//org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1280)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: javax.faces.convert.ConverterException: j_idt8:j_idt10: Could not convert '2022-01-10' to a string.
at javax.faces.api#3.0.0.SP04//javax.faces.convert.DateTimeConverter.getAsString(DateTimeConverter.java:551)
at com.sun.jsf-impl#2.3.14.SP04//com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.getFormattedValue(HtmlBasicRenderer.java:491)
at com.sun.jsf-impl#2.3.14.SP04//com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.getFormattedValue(HtmlBasicRenderer.java:509)
at com.sun.jsf-impl#2.3.14.SP04//com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.getCurrentValue(HtmlBasicRenderer.java:330)
at com.sun.jsf-impl#2.3.14.SP04//com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeEnd(HtmlBasicRenderer.java:143)
at javax.faces.api#3.0.0.SP04//javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:595)
at javax.faces.api#3.0.0.SP04//javax.faces.component.UIComponent.encodeAll(UIComponent.java:1654)
at javax.faces.api#3.0.0.SP04//javax.faces.render.Renderer.encodeChildren(Renderer.java:152)
at javax.faces.api#3.0.0.SP04//javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:566)
at javax.faces.api#3.0.0.SP04//javax.faces.component.UIComponent.encodeAll(UIComponent.java:1647)
at javax.faces.api#3.0.0.SP04//javax.faces.component.UIComponent.encodeAll(UIComponent.java:1650)
at javax.faces.api#3.0.0.SP04//javax.faces.component.UIComponent.encodeAll(UIComponent.java:1650)
at com.sun.jsf-impl#2.3.14.SP04//com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:468)
at com.sun.jsf-impl#2.3.14.SP04//com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:170)
at javax.faces.api#3.0.0.SP04//javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:132)
at javax.faces.api#3.0.0.SP04//javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:132)
at com.sun.jsf-impl#2.3.14.SP04//com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:102)
at com.sun.jsf-impl#2.3.14.SP04//com.sun.faces.lifecycle.Phase.doPhase(Phase.java:76)
at com.sun.jsf-impl#2.3.14.SP04//com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:199)
at javax.faces.api#3.0.0.SP04//javax.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:708)
... 50 more
Caused by: java.lang.IllegalArgumentException: Cannot format given Object as a Date
at java.base/java.text.DateFormat.format(DateFormat.java:338)
at java.base/java.text.Format.format(Format.java:158)
at javax.faces.api#3.0.0.SP04//javax.faces.convert.DateTimeConverter$FormatWrapper.format(DateTimeConverter.java:495)
at javax.faces.api#3.0.0.SP04//javax.faces.convert.DateTimeConverter$FormatWrapper.access$300(DateTimeConverter.java:470)
at javax.faces.api#3.0.0.SP04//javax.faces.convert.DateTimeConverter.getAsString(DateTimeConverter.java:544)
... 69 more

You do not need a custom converter for this. Just use the built-in <f:convertDateTime>. Since version 2.3 it natively supports java.time.* types such as LocalDate. You only need to set the type attribute of the <f:convertDateTime> conform the documentation and set the pattern attribute to the desired pattern.
So, delete the DateConverter altogether and rewrite your XHTML file as follows:
<h:inputText ... value="#{bean.localDate}">
<f:convertDateTime type="localDate" pattern="dd.MM.yyyy" />
...
</h:inputText>
Do note that the converter runs before all validators and thus the Object value argument in any validator will represent the already-converted LocalDate instance and thus not a String.

This worked for me. I have got the same error.
My project the JSF version is 2.0
<ui:composition xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"/>
<h:outputText value="#{user.birthDate}">
<f:converter converterId="localDateConverter" pattern="dd-MMM-yyyy"/>
</h:outputText>

Related

Is a value put to viewScope map in EL without explicit converting always cast to java.lang.String?

The value in f:selectItem is an Integer (Const.DB_NEW_DATASET) but the output of testlistener is always java.lang.String. That's not what I had expected.
xhtml
<f:metadata>
<f:importConstants type="foo.bar.Const" />
</f:metadata>
<h:selectOneListbox value="#{viewScope.foo}">
<f:selectItem
itemValue="#{Const.DB_NEW_DATASET}"
itemLabel="foo" />
<f:selectItem
itemValue="#{Const.DB_NEW_DATASET}"
itemLabel="bar" />
<f:ajax listener="#{myBean.testlistener}" />
</h:selectOneListbox>
bean
#Named
#ViewScoped
public class MyBean implements Serializable {
#Inject
#ViewMap
private Map<String, Object> viewMap;
public void testlistener() {
System.out.println(viewMap.get('foo').getClass());
}
}
public class Const {
public static final Integer DB_NEW_DATASET = -1;
}
Mojarra 2.3.9.SP01
It's actually not "cast to java.lang.String" at all. It's just the default type of ServletRequest#getParameter() which is then left unconverted by JSF.
This is because the ValueExpression#getType() of #{viewScope.foo} returns java.lang.Object and thus JSF won't perform any automatic conversion against any registered #FacesConverter(forClass).
You need to explicitly specify the built-in javax.faces.Integer converter which is essentially a #FacesConverter(forClass=java.lang.Integer).
<h:selectOneListbox ... converterId="javax.faces.Integer">
This is not necessary if you're using e.g. #{bean.foo} with a private Integer foo, because this way the ValueExpression#getType() will return java.lang.Integer and thus JSF can find the built-in converter.
See also:
Why does JSF put String values in a Map<..., Integer>? And how to work around it?
Conversion Error setting value for 'null Converter' - Why do I need a Converter in JSF?

Conversion Error setting value 'dbaccess.persistence.Employee[id=66666666]' for 'null Converter'

Here's a snippet of the form I'm trying to submit:
<h:outputText value="Employees"></h:outputText>
<h:selectManyListbox id="employees"
value="#{lookupControl.memberEmployees}"
converter="#{employeeConverter}">
<f:selectItems value="#{lookupControl.employees}"
var="emp"
itemLabel="#{emp.EMPLOYEE_NUMBER}"
itemValue="#{emp}"/>
</h:selectManyListbox>
<h:message id="employeesMsg"
for="employees"
errorStyle="color:red; display:block"
styleClass="errorMessage"/>
<h:outputText value="Project Lead"></h:outputText>
<h:selectOneListbox id="projectLead"
value="#{lookupControl.chosenLead}"
converter="#{employeeConverter}">
<f:selectItems value="#{lookupControl.employees}"
var="emp"
itemLabel="#{emp.EMPLOYEE_NUMBER}"
itemValue="#{emp}"/>
</h:selectOneListbox>
<h:message id="projectLeadMsg"
for="projectLead"
errorStyle="color:red; display:block"
styleClass="errorMessage"/>
And here's the converter employeeConverter:
#FacesConverter(value = "employeeConverter")
public class EmployeeConverter implements Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
// hack to get an em
HelperBean helper = FacesContext.getCurrentInstance().getApplication().evaluateExpressionGet(context, "#{helperBean}", HelperBean.class);
EntityManager em = helper.getEm();
System.out.println(value);
Employee tmp = DBHelper.findEmployee(em, value);
return tmp;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
Employee tmp = (Employee) value;
return tmp.getEMPLOYEE_NUMBER();
}
}
The idea being that a "Project" (the object being created when this form is submitted) has a list of members (List<Employee>) and a team leader (Employee). When I try submitting the form, I get a message along the lines of:
Conversion Error setting value 'dbaccess.persistence.Employee[id=66666666]' for 'null Converter'.
It's saying it can't convert from a String to an Employee, but it worked for the field right above it. I'm a little confused.
The "null converter" is the exception that the converter instance cannot be found. Since you're referencing the converter as a managed bean by converter="#{employeeConverter}, it would only be found if it's annotated with #javax.faces.bean.ManagedBean
Add #ManagedBean(name = "employeeConverterBean") into class EmployeeConverter
#ManagedBean(name = "employeeConverterBean")
#FacesConverter(value = "employeeConverter")
public class EmployeeConverter implements Converter {
and use converter="#{employeeConverterBean}" instead of converter="#{employeeConverter}"
You are referring to a scoped variable in your converter= attribute, but #FacesConverter does not create a scoped variable. Rather, it registers your converter class with the converter ID you specify.
From the documentation for FacesConverter.value:
The value of this annotation attribute is taken to be the converter-id …
Remove the converter= attribute entirely from your h:selectManyListbox, and instead, add a nested f:converter element:
<h:selectManyListbox id="employees"
value="#{lookupControl.memberEmployees}">
<f:converter converterId="employeeConverter"/>
<f:selectItems value="#{lookupControl.employees}"
var="emp"
itemLabel="#{emp.EMPLOYEE_NUMBER}"
itemValue="#{emp}"/>
</h:selectManyListbox>
Update: I'd always taken the tag documentation literally, which says the attribute's value "must evaluate to javax.faces.convert.Converter". BalusC points out that a nested f:converter is not needed; passing a literal converter ID in the converter= attribute will work:
<h:selectManyListbox id="employees"
value="#{lookupControl.memberEmployees}"
converter="employeeConverter">
<f:selectItems value="#{lookupControl.employees}"
var="emp"
itemLabel="#{emp.EMPLOYEE_NUMBER}"
itemValue="#{emp}"/>
</h:selectManyListbox>
I had never felt comfortable doing that in the past, without a documented guarantee that it works. I just looked through the JSF specification and found this under its "Standard HTML RenderKit Tag Library" section:
The following action must be taken to handle the value of the converter property. If isLiteralText() on the converter property returns true, get the value of the property and treat it as a converterId by passing it as the argument to the createConverter() method of the Application instance for this webapp, then pass the created Converter to the setConverter() method of the component for this tag.
So yes, passing a converter-id in the converter= attribute is completely supported.

Using converters in data table filters in PrimeFaces 5.0 final

Given the following XHTML code (regarding PrimeFaces 5.0 final). New changes to data table filters can be visible here.
<p:dataTable id="dataTable" var="row" value="#{testManagedBean}"
lazy="true"
rowKey="#{row.transporterId}"
widgetVar="dataTableUIWidget">
<p:column id="id" headerText="Id" sortBy="#{row.transporterId}">
<h:outputText value="#{row.transporterId}"/>
</p:column>
<p:column id="transporter" headerText="Transporter" filterBy="#{row.transporterName}">
<f:facet name="filter">
<p:inputText onkeyup="PF('dataTableUIWidget').filter();"/>
</f:facet>
<h:outputText value="#{row.transporterName}"/>
</p:column>
</p:dataTable>
And the following is the faces converter to trim leading and trailing spaces from a string.
#FacesConverter(forClass=String.class)
public final class StringTrimmer implements Converter
{
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
return value != null ? value.trim() : null;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return (String) value;
}
}
Can this converter be applied globally to all filters of type string (including other UI components which is already applied) as specified in the data table?
<f:facet name="filter">
<p:inputText onkeyup="PF('dataTableUIWidget').filter();"/>
</f:facet>
Or I have to modify the converter class to have the annotations like,
#ManagedBean
#RequestScoped
public final class StringTrimmer implements Converter
{
//...
}
and then apply this converter manually to all filters in question like so,
<f:facet name="filter">
<p:inputText onkeyup="PF('dataTableUIWidget').filter();" converter="#{stringTrimmer}"/>
</f:facet>
Can this converter somehow be applied globally so that we don't need to explicitly specify converter="#{stringTrimmer}" for all string type filters?
The question should be more related to JSF rather than PrimeFaces.
It's caused because the UIInput#getValue() defaults to Object, not String. As long as you don't explicitly bind the value attribute of an UIInput based component to a backing bean property of a more specific type, like String, no specific converter will be looked up either.
It should work if you change
<p:inputText onkeyup="PF('dataTableUIWidget').filter();"/>
to e.g.
<p:inputText value="#{bean.filter}" onkeyup="PF('dataTableUIWidget').filter();"/>
with a private String filter property (and a getter+setter). But this is indeed clutter if you don't use this property anywhere else in the model.
The alternative is indeed explicitly declaring a converter via the converter attribute. According to #FacesConverter contract, it's not possible to simultaneously declare both a converter ID and a converter for-class on the same converter class like so
#FacesConverter(value="stringTrimmer", forClass=String.class)
public final class StringTrimmer implements Converter {
// ...
}
Only the converter ID would be registered and a warning will be printed to the server log.
WARNING: #FacesConverter is using both value and forClass, only value will be applied.
But, it is possible to have both #ManagedBean and #FacesConverter on the same class. You should only understand that they don't cooperate with each other and that completely independent instances would be created. But this shouldn't harm if the converter is designed to be stateless (i.e. all state is kept within the method block and the class doesn't have any instance variables/dependencies).
#ManagedBean
#ApplicationScoped
#FacesConverter(forClass=String.class)
public final class StringTrimmer implements Converter {
// ...
}
This way you can keep having the benefit of forClass and still be able to reference the converter as a managed bean via #{stringTrimmer} on those components where forClass can't apply.
<p:inputText onkeyup="PF('dataTableUIWidget').filter();" converter="#{stringTrimmer}" />
An alternate to #BalusC answer is to bind the property into a generic map using a helper "getter / setter" wrapper object to not clutter your code with boilerplate bean properties.
PropertyAccessor
public class PropertyAccessor<T> implements Serializable
{
// bean property path
private String property;
// value
private T value;
// getter & setter for value
}
Filter map
Save this map in a request or view scoped bean or in your "DAO" wrapping class.
private final Map<String, PropertyAccessor> filterProperties = new HashMap<>();
/**
* Get default / temporary filter property
*
* #param property Name of property
* #param init Initial default value
*
* #return
*/
public <T> PropertyAccessor<T> getFilterProperty(final String property, final T init)
{
if (!this.filterProperties.containsKey(property))
this.filterProperties.put(property, new PropertyAccessor<T>(property, init));
return this.filterProperties.get(property);
}
Example:
A composite component with a generic dao and a statefull filter with converter and optional default value.
<p:column headerText="Barcode" filterBy="#{tblVarProduct.barcode}>
<f:facet name="filter">
<p:inputText value="#{cc.attrs.dao.getFilterProperty('barcode', null).value}"
converter="BarcodeConverter"
onchange="PF('#{tblProductWidgetVar}').filter();"/>
</f:facet>
<h:outputText value="#{tblVarProduct.barcode}"/>
</p:column>

Pick Custom Object from Select one menu JSF [duplicate]

This question already has answers here:
How to populate options of h:selectOneMenu from database?
(5 answers)
Closed 6 years ago.
I want to pick a custom object from select one menu. It neither shows an error nor values. What should I do?
My xhtml document:
<h:panelGrid columns="2">
<p:outputLabel value="" />
<p:selectOneMenu id="CurrencyMenu" value="#{CurrencyMB.currency}" >
<f:selectItem itemLabel="-- Select Currency--" itemValue="#{null}"/>
<f:selectItems value="#{CurrencyMB.currencyList}" var="currency" itemValue="#{currency.currencyId}" itemLabel="#{currency.currencyName}" >
</f:selectItems>
<p:ajax update="currencyOut" />
</p:selectOneMenu>
<p:outputLabel value="Currency Id : #{CurrencyMB.currency.currencyId}" id="currencyOut" />
</h:panelGrid>
My managedBean class:
#ManagedBean(name = "CurrencyMB")
#RequestScoped
public class CurrencyManagedBean {
private Currency currency;
private List<Currency> currencyList;
public Currency getCurrency() {
return currency;
}
public void setCurrency(Currency currency) {
this.currency = currency;
}
public List<Currency> getCurrencyList() {
currencyList = new ArrayList<Currency>();
currencyList.addAll(getiCurrencyService().getCurrencies());
return currencyList;
}
public void setCurrencyList(List<Currency> currencyList) {
this.currencyList = currencyList;
}
}
You are trying to map a Java object of class Currency to a string that comes as a HTTP request parameter. A converter is intended to be used in a situation when you need to create an object from a its string representation, and vice versa, like in the situation you faced.
Basically there are two approaches.
1. Utilize converter.
With this approach you define item value as a Currency object and use a converter to create string representation from an object and recreate an object back from a string. For the converter part, just follow the tutorial Luiggi pointed at. Basically you need to create a class that implements Converter, annotate it with #FacesConverter("currencyConverter") to be able to refer to the converter by id, like in converter="currencyConverter" attribute of a JSF tag:
<p:selectOneMenu id="CurrencyMenu" value="#{CurrencyMB.currency}" converter="currencyConverter">
<f:selectItems value="#{CurrencyMB.currencyList}" var="currency" itemValue="#{currency}" itemLabel="#{currency.currencyName}" />
<p:ajax update="currencyOut" />
</p:selectOneMenu>
2. Utilize plain Strings (or java primitive wrappers).
With this approach you bind item values, as well as user selection to a bean property of String type, and not to an actual object. Using it this way you won't need any converter, and string values will be set for you:
<p:selectOneMenu id="CurrencyMenu" value="#{CurrencyMB.currencyName}">
<f:selectItems value="#{CurrencyMB.currencyList}" var="currency" itemValue="#{currency.currencyName}" itemLabel="#{currency.currencyName}" />
<p:ajax update="currencyOut" />
</p:selectOneMenu>
Finally, it is worth reading the question to the answer Why selectOneMenu Send ItemLabel to the converter?.
You can create Converter for your Custom Object Currency.
Step 1: Create a Converter class and Implement javax.faces.convert.Converter Interface,Override getAsObject and getAsString methods and write your logic for String to Object Conversion and Object to String Conversion.
Step 2: Simply declare something like #FacesConverter("currencyConverter") in your converter class or If you want use Spring Inject or Autowired Annotation in Converter class declare your Converter Class with #Component("currencyConverter") Annotation and don't use #FacesConverter.And your converter class should in component scan package.
Step 3: Declare your converter in Selectonemenu Using converter property.
If you still have any problem please refer this link
http://www.techpages.org/jsf/jsf-custom-object-converter-from-selectonemenu/2428/

s:selectItems on List of String?

I am using seam 2.2.2.Final on JBoss AS 5. I am working on a multi-page wizard.On my first page, user will be able to enter several business names separated by a new line on a textarea.
<s:decorate id="businessNameTextAreaField" template="layout/edit.xhtml">
<ui:define name="label">Business Names</ui:define>
<h:inputTextarea id="businessNameTextArea"
cols="80"
rows="3"
required="true"
value="#{businessNameHome.instance.businessNameTextArea}"/>
</s:decorate>
Upon submission of the page, the system parses the inputed value and splits it into a list of strings
public String checkBusinessNames(){
String businessNameTextArea = this.getInstance().getbusinessNameTextArea();
String[] businessNameTextAreaArray = businessNameTextArea.split("\\n");
List<SelectItem> businessNameChoices = new ArrayList<SelectItem>();
for(String businessNameText: businessNameTextAreaArray){
businessNameChoices.add(new SelectItem(businessNameText));
}
this.getInstance().setBusinessNameChoices(businessNameChoices);
return "valid";
}
The user is then asked to select from the list of valid business names to register
<s:decorate id="businessNameRegisterListField" template="layout/edit.xhtml">
<ui:define name="label">Business Name</ui:define>
<h:selectManyCheckbox value="#{businessNameHome.instance.selectedbusinessName}" layout="pageDirection" immediate="true" >
<s:selectItems value="#{businessNameHome.instance.businessNameChoices}" var="bn" label="#{bn.label}" /> </h:selectManyCheckbox>
</s:decorate>
selectedbusinessName is of type String while businessNameChoices is of List
Upon submission of the page, what is submitted as business names is something like this:
javax.faces.model.SelectItem#135aa7c
I have tried putting an itemValue on the s:selectItems but I get another error which is "Value is not valid"
Tried to use <s:convertEntity> but gets a NumberFormatException
I have also tried to create my own converter
public class BusinessNameBeanConverter implements javax.faces.convert.Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent cmp, String value) {
// TODO Auto-generated method stub
System.out.println("getAsObject "+value);
return value;
}
#Override
public String getAsString(FacesContext context, UIComponent cmp, Object value) {
// TODO Auto-generated method stub
System.out.println("getAsString "+((SelectItem)value).getValue());
return ((SelectItem)value).getValue();
}
}
but I still get the same "Value is not valid" error.
I don't know what to do anymore. Please help.
Thanks,
Nicholas
Change
<s:selectItems value="#{businessNameHome.instance.businessNameChoices}" var="bn" label="#{bn.label}" />
to
<f:selectItems value="#{businessNameHome.instance.businessNameChoices}" />
You've namely already a List<SelectItem>, not a List<SomeObject> for which <s:selectItems> is useful.
Don't forget to remove the converter, it makes no sense.

Resources