I do not why although I verify everything which is right. Anyone know?
I tried to debug:
- getAsString() return ID (that's right)
- when I submitted - getAsObject() always throw exception because the label values was always passed instead of ID values.
My code as below:
my xhtml file:
<div class="ui-grid-row" style="margin-top: 5px; margin-bottom: 5px;">
<div class="ui-grid-col-2 pdt4">
<p:outputLabel for="txtApprovalScheduler"
value="#{lang['workforce.category.parttimeManagement.approved.scheduler']}"/>
</div>
<div class="ui-grid-col-2">
<p:selectOneMenu value="#{parttimeController.selectedAgentDTO}"
id="txtApprovalScheduler"
filterMatchMode="contains" editable="true"
style="width: 86%;"
required="true"
requiredMessage="#{lang['workforce.category.parttimeManagement.approved.scheduler.missing']}">
<f:converter converterId="agentConverter"/>
<f:selectItem itemValue="" itemLabel="#{lang['wf.common.choose']}"/>
<f:selectItems value="#{parttimeController.agentDTOs}" var="agentItem1"
itemLabel="#{agentItem1.userName}"
itemValue="#{agentItem1}"/>
</p:selectOneMenu>
</div>
<div class="ui-grid-col-2 pdt4">
<p:outputLabel for="txtApprovalRegister"
value="#{lang['workforce.category.parttimeManagement.approved.register']}"/>
</div>
<div class="ui-grid-col-2">
<p:selectOneMenu value="#{parttimeController.selectedAgentDTOForRegister}"
id="txtApprovalRegister" editable="true"
filterMatchMode="contains" style="width: 86%; font-size: 12px !important;"
required="true"
requiredMessage="#{lang['workforce.category.parttimeManagement.approved.register.missing']}">
<f:converter converterId="agentConverter"/>
<f:selectItem itemValue="" itemLabel="#{lang['wf.common.choose']}"/>
<f:selectItems value="#{parttimeController.agentDTOs}" var="item1"
itemLabel="#{item1.userName}"
itemValue="#{item1}"/>
</p:selectOneMenu>
</div>
</div>
My Converter:
#FacesConverter(forClass = AgentDTO.class,value = "agentConverter")
public class AgentConverter implements Converter {
public static List<AgentDTO> listAgentDTOs;
#Override
public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String agentId) {
if (agentId.trim().equals("")) {
return null;
} else {
try {
Long number = Long.parseLong(agentId);
for (AgentDTO a : listAgentDTOs) {
if (a.getAgentId() == number) {
return a;
}
}
} catch (NumberFormatException exception) {
throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Conversion Error", "Not a valid data"));
}
}
return null;
}
#Override
public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object value) {
if (value == null || value.equals("") || "-1".equals(value)) {
return "";
} else {
String result = String.valueOf(((AgentDTO) value).getAgentId());
return result;
}
}
}
My bean:
#Component
#Scope("view")
#ManagedBean(name = "parttimeController")
public class ParttimeController extends BaseController implements Serializable {
private AgentDTO selectedAgentDTO;
private AgentDTO selectedAgentDTOForRegister;
private List<AgentDTO> agentDTOs;
.... getter/setter and initiallize AgentCenvert.listAgentDTOs
My class:
public class AgentDTO{
private Long agentId;
private String userName;
....getter/setter
}
I found out the reason - I only remove editable attribute in selectOneMenu. So getAsObject() will pass a value instead of a label
Related
I'm working with a web application with the following technologies
spring 4.3
JSF 2.2.14
PrimeFaces 6.1
Omnifaces 2.6.4
I need to validate an h:inputText, and I'm trying to use the javax.faces.validator.Validator interface.
All is working well but when the validation fail, I'm not able to retrieve the label of the field, that is stored in a p:outputLabel using the "for" attribute.
Facelets code
<p:outputLabel id="selectedAdvPriceOutputLabel" for="selectedAdvPrice" value="#{msg['prezzo']}"/>
<h:inputText id="selectedAdvPrice"
value="#{addAdvertisingController.advertisingBean.price}"
class="form-control"
converter="javax.faces.BigDecimal"
required="#{empty param[draftSave.clientId] and empty param[draftSaveXS.clientId]}"
requiredMessage="#{msg['prezzo']} #{msg['campoObbligatorio']}">
<f:validator binding="#{numberGreaterThanZeroJsfValidator}" />
</h:inputText>
Validator - validate method
public void validate(FacesContext context, UIComponent component, Object value) {
if (value != null) {
String v = value.toString();
if (StringUtils.isNotEmpty(v)) {
try {
BigDecimal bd = new BigDecimal(v);
if(bd.compareTo(BigDecimal.ZERO) <= 0){
// how to retrieve the field label???
FacesMessage msg = new FacesMessage("messageWithout label", "messageWithout label");
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(msg, new IllegalArgumentException(exceptionMessage));
}
} catch (NumberFormatException e) {
FacesMessage msg = new FacesMessage("messageWithout label", "messageWithout label");
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(msg, new IllegalArgumentException(exceptionMessage));
}
}
}
}
How can I retrieve the value attribute of the p:outputLabel linked to the h:inputText that is not passing the validation?
Thank you
According to Primefaces User's Guide --> 3.93 OutputLabel
Auto Label
OutputLabel sets its value as the label of the target component to be displayed in validation errors so the target component
does not need to define the label attribute again.
<h:outputLabel for="input" value="Field" />
<p:inputText id="input" value="#{bean.text}" label="Field"/>
can be rewritten as;
<p:outputLabel for="input" value="Field" />
<p:inputText id="input" value="#{bean.text}" />
It means, that OutputLabel simply sets the label attributte of a component to which the label is attached.
Just retrieve this attributte in the validator, for example in this way:
public void validate(FacesContext context, UIComponent component, Object value) {
Object labelObj = component.getAttributes().get("label");
String label = (labelObj!=null) ? labelObj.toString() : "Unknown label";
.....
.....
// how to retrieve the field label???
String message = String.format("%s : My conversion error message", label);
FacesMessage msg = new FacesMessage(message,message) ;
.....
.....
I've tested it and it works for both p:inputText and h:inputText components.
Hi, I've debugged the code and component.getAttributes().get("label")
is null
I've tested it again on JSF 2.2/Primefaces 6.1/Wildfy 10.x and it works.
Here is a simple demo project on GitHub link
index.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head></h:head>
<h:body>
<h:form>
<p:panel id="panel" header="Form" style="margin-bottom:10px;">
<p:messages id="messages" />
<h:panelGrid columns="2" cellpadding="5">
<p:outputLabel id="label1_id"
for="input1_id" value="This Is My label for h:input" />
<h:inputText id="input1_id" value="#{myBean.price1}"
required="true" >
<f:validator validatorId="MyValidator" />
</h:inputText>
<p:outputLabel id="label2_id"
for="input2_id" value="This Is My label for p:input" />
<p:inputText id="input2_id" value="#{myBean.price2}" required="true">
<f:validator validatorId="MyValidator" />
</p:inputText>
</h:panelGrid>
<p:commandButton update="panel" value="Submit" />
</p:panel>
</h:form>
</h:body>
</html>
bean
#Named
#SessionScoped
public class MyBean implements Serializable {
private static final long serialVersionUID = 5455916691447931918L;
private Integer price1;
private Integer price2;
public Integer getPrice2() {
return price2;
}
public void setPrice2(Integer price2) {
this.price2 = price2;
}
public Integer getPrice1() {
return price1;
}
public void setPrice1(Integer price1) {
this.price1 = price1;
}
}
Validator
#FacesValidator("MyValidator")
public class MyValidator implements Validator {
public void validate(FacesContext context, UIComponent component, Object value) {
Object labelObj = component.getAttributes().get("label");
String label = (labelObj!=null) ? labelObj.toString() : "Unknown label";
if (value != null) {
String v = value.toString();
if (null != v && !v.isEmpty()) {
try {
BigDecimal bd = new BigDecimal(v);
if (bd.compareTo(BigDecimal.ZERO) <= 0) {
// how to retrieve the field label???
String message = String.format("%s : Value must be greater than 0", label);
FacesMessage msg = new FacesMessage(message,message) ;
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(msg, new IllegalArgumentException("Validator exception:" + message));
}
} catch (NumberFormatException e) {
String message = String.format("%s : Value must be a number", label);
FacesMessage msg = new FacesMessage(message,message);
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(msg, new IllegalArgumentException("Validator exception:" + message));
}
}
}
}
}
And a result is:
Some things that may help or are common:
remove id from *:outputLabel as this is not needed
use validatorMessage="#{bundle.SOME_FIELD_VALIDATION_ERROR}" to have a localizable message, if your validator is throwing javax.faces.validator.ValidatorException (you can import this above your validator class, of course)
get rid of the code for the label-retrieval, see above validatorMessage field
<f:validator binding="#{someValidator}" /> seem to cause more problems, common way is: <f:validator validatorId="SomeFooValidator" /> within *:inputText (you have to make it non-self-closing)
and then annotate your validator class with #FacesValidator ("SomeFooValidator") (javax.faces.validator.FacesValidator)
Are you using JSF2.2?
I am trying to do some work when the h:commandButton is clicked. I am using jsf 2.2 as I am sending multipart data. I have 3 commandButtons in my form, The first 2 are working fine whereas the 3rd commandButton is not working.
This is my jsf page code:
<h:form id="userSetup" enctype="multipart/form-data" >
<div style=" margin-left: 250px; padding-top: 10px;width: 150px;margin-top: 100px;">
<img id="profile-picture" src="http://www.aspirehire.co.uk/aspirehire-co-uk/_img/profile.svg" height="120" width="120"></img>
<button onclick="addProfilePicture();return false;" class="cff-button" style="margin-top: 10px;margin-left: -10px;white-space: normal;width: 150px;">Add Profile Picture</button>
</div>
<br/><br/>
<h:inputFile id="profilePicture" value="#{uploader.profilePicture}" a:hidden="true" onchange="displayImage(this)">
<f:validator validatorId="imageValidator"></f:validator>
</h:inputFile>
<div class="user-input-div">
<h:messages id="response-message" style="color: red"></h:messages>
<h:inputText id="skills" a:placeholder="Skills" class="cff-inputText " ></h:inputText>
<br/><br/>
<button class="cff-button " style=" white-space: normal" onclick="toggleCertificateInput('#{certificateInput.clientId}',true);return false">Add Certificate</button>
<br/><br/>
<h:panelGroup id="certificate-input" layout="block" binding="#{certificateInput}" a:hidden="true" >
<h:inputText id="certificateName" value="#{uploader.certificateName}" class="cff-inputText" a:required="true" a:placeholder="Certificate Name" binding="#{certificateName}">
<f:validator validatorId="stringValidator"></f:validator>
</h:inputText>
<h:inputText id="certificateLink" value="#{uploader.certificateLink}" class="cff-inputText" a:placeholder="Link" binding="#{certificateLink}">
<f:validator validatorId="urlValidator"></f:validator>
</h:inputText>
<h:commandButton value="Save Certificate" class="cff-button" action="#{uploader.saveCertificate()}" >
<f:ajax execute="certificateName certificateLink response-message" onevent="function hide(data){ if(data.status === 'success'){ toggleCertificateInput('#{certificateInput.clientId}',false) } }" render="userSetup:certificate-output certificateName certificateLink response-message"></f:ajax>
</h:commandButton>
<button class="cff-button" onclick="toggleCertificateInput('#{certificateInput.clientId}',false);return false">Cancel</button>
</h:panelGroup>
<h:panelGroup id="certificate-output-div" binding="#{certificateOutput}">
<h:dataTable var="certificate" id="certificate-output" value="#{uploader.certificates}">
<h:column>
<h:outputText id="certificate-output-name" value="#{certificate.certificateName} " class="certificate-name"></h:outputText>
<h:outputLink id="certificate-output-link" class="cff-link" value=" #{certificate.link}">view certificate</h:outputLink>
<span id="remove" onclick="removeCertificate('#{removeCertificate.clientId}');" class="remove"> ×</span>
<h:commandButton a:hidden="true" binding="#{removeCertificate}" id="removeCertificate" action="#{uploader.removeCertificate(certificate)}" value="Remove" class="cff-button" >
<f:ajax execute=" certificate-output certificate-output-link certificate-output-name " render="userSetup:certificate-output response-message"></f:ajax>
</h:commandButton>
</h:column>
</h:dataTable>
</h:panelGroup>
//This command button is not working
<h:commandButton class="cff-button" action="#{uploader.saveAndContinue()}" value="Save and Continue">
<f:ajax execute="#form"></f:ajax>
</h:commandButton>
</div>
</h:form>
This is my model code:
#ManagedBean(name="uploader")
#ViewScoped
public class userDataUploader {
private String about_Yourself;
private String skills;
private List<Certificates> certificates;
private Part profilePicture;
private String certificateName;
private String certificateLink;
#ManagedProperty(value="#{userData}")
private User userData;
#PostConstruct
public void init(){
certificates = new ArrayList<Certificates>();
}
public List<Certificates> getCertificates() {
return certificates;
}
public void setCertificates(List<Certificates> certificates) {
this.certificates = certificates;
}
public Part getProfilePicture() {
return profilePicture;
}
public void setProfilePicture(Part profilePicture) {
this.profilePicture = profilePicture;
}
public String getAbout_Yourself() {
return about_Yourself;
}
public void setAbout_Yourself(String about_Yourself) {
this.about_Yourself = about_Yourself;
}
public String getSkills() {
return skills;
}
public void setSkills(String skills) {
this.skills = skills;
}
public User getUserData() {
return userData;
}
public void setUserData(User userData) {
this.userData = userData;
}
public String getCertificateName() {
return certificateName;
}
public void setCertificateName(String certificateName) {
this.certificateName = certificateName;
}
public String getCertificateLink() {
return certificateLink;
}
public void setCertificateLink(String certificateLink) {
this.certificateLink = certificateLink;
}
public void addCertificate(){
out.println("about to add new Certificate");
}
public void removeCertificate(Certificates certificate){
out.println("about to remove certificate " + certificate.getCertificateName() + " " + certificate.getLink() );
certificates.remove(certificate);
out.println(certificates.isEmpty());
}
public void saveCertificate(){
Certificates certificate = new Certificates();
certificate.setCertificateName(certificateName);
out.println(certificateName + "\n" + certificateLink);
certificate.setLink(certificateLink);
certificates.add(certificate);
out.println("new certificate has been added");
certificateName = null;
certificateLink = null;
out.println(certificates.isEmpty());
}
public String saveAndContinue(){
out.println("welcome to save and continue function");
out.println(skills);
boolean result = true;
Uploader uploader = new Uploader(userData,certificates,getSkillsArray(),profilePicture);
String returnString = "success";
out.println("about to save all data");
try {
uploader.saveAllData();
} catch (Exception ex) {
out.println(ex);
result = false;
}
if(!result){
returnString = "false";
}
out.println("return string is " + returnString);
return returnString;
}
private String[] getSkillsArray(){
return skills.split(" ");
}
}
Can somebody please tell me where I am going wrong? ThankYou.
My form is working if editable is set to true but not when it's false. When false the submit action method is not even called. I need it to be false (not editable so I can store the correct value in db).
This is the menu I added.
<tr><td>
<h:outputLabel for="country">#{registering.Country}: </h:outputLabel></td>
<td><p:selectOneMenu editable="false" id="country" required="true" requiredMessage="Required" value="#{subscribeUser.user.countryBean}" converter="#{countriesConverter}" effect="fold" >
<f:selectItem itemValue="#{null}" itemLabel="#{registering.SelectCountry}" />
<f:selectItems value="#{countriesConverter.countries}" var="country" itemLabel="#{country.shortName}" itemValue="#{country}" />
</p:selectOneMenu></td><td></td><td>
<span class="error"><h:message id="countryMessage" for="country"/></span></td>
</tr>
Notice that the select one menu has editable="false" it doesn't work in that case. But if I put editable="true" it works.
here is the full form, last 2 fields are problematic:
<h:form>
<table class="registration">
<!-- username -->
<tr><td>
<h:outputLabel for="username">#{registering.Username}: </h:outputLabel></td><td>
<p:inputText id="username" value="#{subscribeUser.user.username}"
validator="#{usernameValidator.validate}" maxlength="#{values.small}">
<f:passThroughAttribute name="required" value="true"/>
<f:ajax event="blur" render="usernameCheck usernameMessage submit"></f:ajax>
</p:inputText></td><td>
<h:panelGroup id="usernameCheck">
<h:graphicImage library="images/icons" name="failed_indicator.png" rendered="#{usernameValidator.isIndicatorVisible.usernameFailed}"></h:graphicImage>
<h:graphicImage library="images/icons" name="success_indicator.png" rendered="#{usernameValidator.isIndicatorVisible.usernameSuccess}"></h:graphicImage>
</h:panelGroup></td><td>
<span class="error"><h:message id="usernameMessage" for="username"/></span></td>
</tr>
<!-- password -->
<tr><td>
<h:outputLabel for="password">#{registering.Password}: </h:outputLabel></td><td>
<p:password id="password" value="#{subscribeUser.userCredential.password}" feedback="true"
promptLabel="#{registering.PleaseEnterPass}" weakLabel="#{registering.Weak}"
goodLabel="#{registering.Good}" strongLabel="#{registering.Strong}"
requiredMessage="#{registering.reqPassword}"
validator="#{passwordValidator.validate}">
<f:passThroughAttribute name="required" value="true"/>
<f:attribute name="confirm" value="#{confirmPassword}" />
<f:passThroughAttribute name="required" value="true"/>
<f:ajax event="blur" execute="password confirmPassword" render="passwordMessage passwordCheck confpasswordCheck submit"></f:ajax>
</p:password></td><td>
<h:panelGroup id="passwordCheck">
<h:graphicImage library="images/icons" name="failed_indicator.png" rendered="#{passwordValidator.isIndicatorVisible.passwordFailed}"></h:graphicImage>
<h:graphicImage library="images/icons" name="success_indicator.png" rendered="#{passwordValidator.isIndicatorVisible.passwordSuccess}"></h:graphicImage>
</h:panelGroup>
</td><td>
<span class="error"><h:message id="passwordMessage" for="password"/></span></td>
</tr>
<!-- Confirm password -->
<tr><td>
<h:outputLabel for="confirmPassword" value="#{registering.ConfirmPass}: "/></td><td>
<p:password id="confirmPassword" required="true"
requiredMessage="#{registering.PleaseConfirmPassword}"
binding="#{confirmPassword}">
<f:passThroughAttribute name="required" value="true"/>
<f:ajax event="blur" execute="password confirmPassword" render="passwordMessage passwordCheck confpasswordCheck submit"></f:ajax>
</p:password> </td><td>
<h:panelGroup id="confpasswordCheck">
<h:graphicImage library="images/icons" name="failed_indicator.png" rendered="#{passwordValidator.isIndicatorVisible.passwordFailed}"></h:graphicImage>
<h:graphicImage library="images/icons" name="success_indicator.png" rendered="#{passwordValidator.isIndicatorVisible.passwordSuccess}"></h:graphicImage>
</h:panelGroup>
</td><td>
<span class="error"><h:message id="passwordConfMessage" for="confirmPassword" /></span></td>
</tr>
<!-- Email -->
<tr><td>
<h:outputLabel for="email">#{registering.Email}: </h:outputLabel></td><td>
<p:inputText id="email" required="true" value="#{subscribeUser.user.email}"
validator="#{emailValidator.validate}"
requiredMessage="#{registering.reqEmail}">
<f:passThroughAttribute name="required" value="true"/>
<f:passThroughAttribute name="type" value="email"/>
<f:passThroughAttribute name="maxlength" value="100"/>
<f:ajax event="blur" render="emailCheck emailMessage submit"></f:ajax>
</p:inputText></td><td>
<h:panelGroup id="emailCheck">
<h:graphicImage library="images/icons" name="failed_indicator.png" rendered="#{emailValidator.isIndicatorVisible.emailFailed}"></h:graphicImage>
<h:graphicImage library="images/icons" name="success_indicator.png" rendered="#{emailValidator.isIndicatorVisible.emailSuccess}"></h:graphicImage>
</h:panelGroup> </td><td>
<span class="error"><h:message id="emailMessage" for="email"/></span></td>
</tr>
<!-- Country -->
<tr><td>
<h:outputLabel for="country">#{registering.Country}: </h:outputLabel></td>
<td colspan="3"><p:selectOneMenu required="true" editable="true" id="country" value="#{subscribeUser.user.countryBean}" converter="#{countriesConverter}" effect="fold">
<f:selectItems value="#{countriesConverter.countries}" var="country" itemLabel="#{country.shortName}" itemValue="#{country}" />
</p:selectOneMenu></td>
</tr>
<!-- Timezone -->
<tr><td>
<h:outputLabel for="timezone">#{registering.Timezone}: </h:outputLabel></td>
<td colspan="3">
<p:selectOneMenu id="timezone" editable="true" required="true" value="#{subscribeUser.user.timezoneOffset}" converter="#{timezonesConverter}" effect="fold" >
<f:selectItems value="#{timezonesConverter.timezonesList}" var="timezone" itemLabel="#{timezone.name}" itemValue="#{timezone}" />
</p:selectOneMenu></td>
</tr>
</table>
<div class="areYouARobot" ><div class="captchaLabel">#{registering.AreYouARobot}</div>
<!-- <div class="g-recaptcha" data-sitekey="6LdFTgcTAAAAAHQeLLEKPE-of2si0GrwuZXoEAHb"></div> --></div>
<div class="submit">
<p:commandButton value="#{registering.Submit}" id="submit" action="#{subscribeUser.inscrireUser}" icon="ui-icon-disk"
disabled="#{!(usernameValidator.ok and passwordValidator.ok and emailValidator.ok)}" >
</p:commandButton></div>
</h:form>
Here is the country converter:
#ManagedBean
public class CountriesConverter implements Converter {
private List<Country> countries;
private List<String> countriesStr;
private List<Integer> countriesId;
private Country country;
#EJB
private CountriesService cs;
#PostConstruct
public void init() {
this.countries = cs.getAllCountries();
this.countriesStr = new ArrayList<String>();
this.countriesId = new ArrayList<Integer>();
for (Country c : countries) {
this.countriesStr.add(c.getShortName());
}
for (Country c : countries) {
this.countriesId.add(c.getIdCountry());
}
}
#Override
public Country getAsObject(FacesContext ctx, UIComponent component,
String submittedValue) {
if (submittedValue == null || submittedValue.isEmpty()) {
return null;
}
try {
return cs.findByName(submittedValue);
} catch (Exception e) {
return null;
}
}
#Override
public String getAsString(FacesContext fc, UIComponent uic,
Object modelValue) {
Country datCountry = (Country) modelValue;
if (datCountry == null) {
return "";
}
else if (datCountry instanceof Country) {
return datCountry.getShortName();
} else {
return null;
}
}
//get&sets
}
The country entity:
#Entity
#Table(name="countries")
#NamedQuery(name="Country.findAll", query="SELECT c FROM Country c")
public class Country implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private int idCountry;
#Column(name="calling_code")
private String callingCode;
private String cctld;
private String iso2;
private String iso3;
#Column(name="long_name")
private String longName;
private String numcode;
#Column(name="short_name")
private String shortName;
#Column(name="un_member")
private String unMember;
//bi-directional many-to-one association to User
#OneToMany(mappedBy="countryBean")
private List<User> users;
public Country() {
}
//getter & setters
}
My timezone converter:
#ManagedBean
public class TimezonesConverter implements Converter {
private List<Timezone> timezonesList;
private Map<String, Timezone> myMap;
private static final String[] timezonesStr = {
"(GMT -12:00) Eniwetok, Kwajalein",
"etcetera" };
public TimezonesConverter() {
timezonesList = new ArrayList<Timezone>();
myMap = new TreeMap<String, Timezone>();
int offset = -720;
for (String s : timezonesStr) {
Timezone timezone = new Timezone(s, offset);
timezonesList.add(timezone);
myMap.put(s, timezone);
offset += 60;
}
}
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1,
String submittedValue) {
if (submittedValue == null || submittedValue.isEmpty()) {
return null;
}
try {
return myMap.get(submittedValue);
} catch (Exception e) {
return null;
}
}
#Override
public String getAsString(FacesContext arg0, UIComponent arg1,
Object modelValue) {
// casting error here.
Timezone timezone = (Timezone) modelValue;
if (timezone == null) {
return "";
} else if (timezone instanceof Timezone) {
return timezone.getName();
} else {
return null;
}
}
//getters
}
Timezone class:
public class Timezone {
private String name;
private int offset;
public Timezone(String name, int offset) {
this.name = name;
this.value = offset;
}
//getters and setters
}
I commented the timezone thing but when uncommented it gives me this error, which makes no sens to me since the var I put in the timezone menu is a timezone object:
java.lang.ClassCastException: java.lang.Integer cannot be cast to main.java.utils.Timezone
at main.java.converters.TimezonesConverter.getAsString(TimezonesConverter.java:82)
I did a workaround for this but I'm unhappy with it:
#Override
public String getAsString(FacesContext arg0, UIComponent arg1,
Object modelValue) {
int offset = (int) modelValue;
if (modelValue == null) {
return "";
} else {
for (Timezone tz : timezonesList) {
if (tz.getOffset() == offset) {
return tz.getName();
}
}
}
return null;
}
and I switched the value in the form to :
<f:selectItems value="#{timezonesConverter.timezonesList}" var="timezone" itemLabel="#{timezone.name}" itemValue="#{timezone.offset}" />
So instead of the value being a Timezone object (that x reason was considered as an Integer and caused the cast exception), it is the int variable inside the Timezone object that is taken, and that works.
the user entity:
#Entity
#Table(name="users")
#NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private String username;
private String email;
#Column(name="is_enabled")
private int isEnabled;
#Temporal(TemporalType.DATE)
#Column(name="member_since")
private Date memberSince;
#Column(name="profile_pic")
private String profilePic;
private int reputation;
private String role;
private String status;
private int timezoneOffset;
#Column(name="warning_lvl")
private int warningLvl;
private String xxx;
//bi-directional many-to-one association to Friend
#OneToMany(mappedBy="user1")
private List<Friend> friends1;
//bi-directional many-to-one association to Friend
#OneToMany(mappedBy="user2")
private List<Friend> friends2;
//bi-directional many-to-one association to Message
#OneToMany(mappedBy="user1")
private List<Message> messages1;
//bi-directional many-to-one association to Message
#OneToMany(mappedBy="user2")
private List<Message> messages2;
//bi-directional many-to-one association to Thethread
#OneToMany(mappedBy="user1")
private List<Thethread> thethreads1;
//bi-directional many-to-one association to Thethread
#OneToMany(mappedBy="user2")
private List<Thethread> thethreads2;
//bi-directional many-to-one association to Usercfg
#OneToMany(mappedBy="user")
private List<Usercfg> usercfgs;
//bi-directional many-to-one association to Userinfo
#OneToMany(mappedBy="user")
private List<Userinfo> userinfos;
//bi-directional many-to-one association to Country
#ManyToOne
#JoinColumn(name="country")
private Country countryBean;
public User() {
}
// getters & setters
}
The reason why method is not called is, that conversion of values fails.
Country field
CountriesConverter method getAsObject should have return type Object, I expect it's not called at all now.
Country class must implement the equals and hashCode methods.
Timezone field
The timezoneOffset property of the User class must be instance of the Timezone class.
OR
Keep the timezoneOffset int, remove the converter and set the int value using the itemValue attribute. See the example:
<p:selectOneMenu id="timezone" editable="true" required="true"
value="#{subscribeUser.user.timezoneOffset}" effect="fold" >
<f:selectItems value="#{timezonesConverter.timezonesList}" var="timezone"
itemLabel="#{timezone.name}" itemValue="#{timezone.offset}" />
</p:selectOneMenu>
This question already has answers here:
Conversion Error setting value for 'null Converter' - Why do I need a Converter in JSF?
(2 answers)
Closed 6 years ago.
Ok, so I get this error and found no solution working for me (I tried around a lot with annotations like #FacesConverter or #Named instead #ManagedBean etc.) If anybody could point me to the right direction, that would be awesome. BalusC mentioned, that this particular error means, that the converter cannot be found, but the Converter is getting called, as I can see in log messages of JBoss (see log.info calls below in the Converter code). At least I don't get NullPointerExceptions from the Converter anymore (although I can't reproduce why). I'm getting a bit frustrated with JSF, but I'm sure it's my fault and I have overseen something obvious?
The code should be simple enough, I want to set zero, one or more Tags for a Link entity (newLink.tags) with means of a selectManyCheckbox:
This is my XHTML form:
<h:form id="create_link_form" rendered="#{authController.loggedIn}">
<h3>Enter a new Link here:</h3>`
<h:panelGrid columns="3" columnClasses="titleCell">
<h:outputLabel for="name" value="Name:"/>
<h:inputText id="name" value="#{newLink.name}"/>
<p:message for="name" errorClass="invalid"/>
<h:outputLabel for="url" value="URL:"/>
<h:inputText id="url" value="#{newLink.url}"/>
<p:message for="url" errorClass="invalid"/>
<h:outputLabel for="description" value="Description:"/>
<h:inputText id="description" value="#{newLink.description}"/>
<p:message for="description" errorClass="invalid"/>
<h:outputLabel for="shared" value="Shared?:"/>
<h:selectBooleanCheckbox id="shared" label="Shared?:" value="#{newLink.shared}"/>
<p:message for="shared" errorClass="invalid"/>
</h:panelGrid>
<h:outputLabel for="tags" value="Tags:"/>
<h:selectManyCheckbox label="Tags:" id="tags" value="#{newLink.tags}" converter="#{tagConverter}">
<f:selectItems value="#{tags}" var="tag" itemLabel="#{tag.name}" itemValue="#{tag}"/>
</h:selectManyCheckbox>
<h:inputHidden id="owner" value="#{newLink.owner}" name="{authController.loggedInUserName}"/>
<p>
<h:panelGrid columns="2">
<h:commandButton id="create" action="#{linkController.create}" value="Create"
styleClass="create">
</h:commandButton>
<p:messages styleClass="messages" autoUpdate="true" globalOnly="true"/>
</h:panelGrid>
</p>
</h:form>
And this is my Converter:
#RequestScoped
#ManagedBean
public class TagConverter implements Converter {
#Inject
private Logger log;
#Inject
private TagService tagService;
#Override
public Object getAsObject(FacesContext fc, UIComponent uic, String value) {
if (value != null && value.trim().length() > 0) {
try {
log.info("TTagConverter.getAsObject() => having " + value);
Long id = Long.parseLong(value);
Tag tag = tagService.getTagWithId(id);
log.info("TagConverter.getAsObject() => Tag converted: " + tag);
return tag;
} catch (NumberFormatException e) {
throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Conversion Error", "Not a valid tag."));
}
} else {
return null;
}
}
#Override
public String getAsString(FacesContext fc, UIComponent uic, Object object) {
if (object != null) {
if (object instanceof Tag) {
Long id = ((Tag) object).getId();
return id.toString();
} else {
throw new ConverterException(new FacesMessage("There was an Object type error for a "
+ object.getClass() + " in getAsString(" + object + ")"));
}
} else {
return null;
}
}
}
Your managed bean shouldnt implement it.
Create class and implement converter.
#FacesConverter("myConverter")
public class MyConverter implements Converter{
...
}
in your facelets
<h:selectManyCheckbox label="Tags:" id="tags" value="#{newLink.tags}">
<f:selectItems value="#{tags}" var="tag" itemLabel="#{tag.name}" itemValue="#{tag}"/>
<f:converter converterId="myConverter" />
</h:selectManyCheckbox>
Is it clear?
This question already has answers here:
Validation Error: Value is not valid
(3 answers)
Closed 8 years ago.
I keep getting this error addAddress:states: Validation Error: Value is not valid when using <p:selectOneMenu. I tried using the id and got rid of the converter, its doing the same. I tried debugging. Found that the converted is running twice and the last time it is checking blank value and returning null/false. What am I doing wrong? If need any more details let me know?
Code is as follows
Converter
#FacesConverter(value = "statemasterconverter", forClass = Statemaster.class)
public class StateConverter implements Converter {
public String getAsString(FacesContext context, UIComponent component,
Object value) {
return ConversionHelper.getAsString(value);
}
public Object getAsObject(FacesContext context, UIComponent component,
String value) {
return ConversionHelper.getAsObject(Statemaster.class, value);
}
}
Conversion Helper
public final class ConversionHelper {
private ConversionHelper() {
}
#SuppressWarnings("unchecked")
public static <T> T getAsObject(Class<T> returnType, String value) {
BigDecimal id = BigDecimal.ZERO;
if (returnType == null) {
throw new NullPointerException(
"Trying to getAsObject with a null return type.");
}
if (value == null) {
throw new NullPointerException(
"Trying to getAsObject with a null value.");
}
try {
id = BigDecimal.valueOf(Long.parseLong(value));
} catch (NumberFormatException nfe) {
return null;
}
Session session = HibernateUtil.getSessionFactory().openSession();
try {
T r = (T) session.load(returnType, id);
if (r != null)
Hibernate.initialize(r);
return r;
} catch (HibernateException e) {
e.printStackTrace();
} finally {
session.close();
}
return null;
}
public static String getAsString(Object value) {
if (value instanceof Gendermaster) {
Gendermaster result = (Gendermaster) value;
return String.valueOf(result.getGenderid());
} else if (value instanceof Salutationmaster) {
Salutationmaster result = (Salutationmaster) value;
return String.valueOf(result.getSalutationid());
} else if (value instanceof Countrymaster) {
Countrymaster result = (Countrymaster) value;
return String.valueOf(result.getCountryid());
} else if (value instanceof Statemaster) {
Statemaster result = (Statemaster) value;
return String.valueOf(result.getStateid());
}
return null;
}
}
the xhtml code
<p:row>
<p:column>
Country
</p:column>
<p:column>
<p:selectOneMenu id="country"
value="#{customerBean.country.countryid}" required="true">
<f:selectItem itemLabel="Select Country" itemValue="" />
<f:selectItems value="#{customerBean.countrydropdown}"
var="countrymaster"
itemLabel="#{countrymaster.countryname} - #{countrymaster.countrycodeNn}"
itemValue="#{countrymaster.countryid}" />
<p:ajax update="states"
listener="#{customerBean.updateStates()}" />
</p:selectOneMenu>
</p:column>
</p:row>
<p:row>
<p:column>
State
</p:column>
<p:column>
<p:selectOneMenu id="states" required="true"
value="#{customerBean.state}" converter="statemasterconverter">
<f:selectItem itemValue="" itemLabel="Select State" />
<f:selectItems value="#{customerBean.statedropdown}"
var="statemaster"
itemLabel="#{statemaster.statename} - #{statemaster.statecode}"
itemValue="#{statemaster}" />
</p:selectOneMenu>
</p:column>
</p:row>
<p:commandButton id="saveBtn" value="Save Salutation"
update="msgs"
style="float: left;" icon="ui-icon-disk"
actionListener="#{customerBean.saveAddress()}" ajax="true" />
</p:column>
Use event="valueChange" in Ajax. and try to updated whole form by update="#form".
if above code is not work then try update=":id:id" update tag search id within the tag.
let consider this code.
<h:form id="myForm">
<h:sometag id="ineer1">
<p:ajax update="ineer3"/>// it is **not work**
<p:ajax update=":myForm:ineer2:ineer2"/>// it is **work**
</h:sometag>
<h:sometag id="ineer2">
<h:someoutfield id="ineer3"/>
</h:sometag>
<h:/form>
it is working at my end if not work then let me know.
Happy to help :)