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?
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 working with settings part in my project. I want to get the form attributes from the DB like maxlength, minlength, pattern etc.
I want to use my bean class variable as a pattern String. Is that Possible? minlength, maxlength attributes works fine using bean class variable, but validateRegex is not working
Bean code
#Service
class CategoryBean {
String categoryNamePattern;
String showForm(){
categoryNamePattern = "([a-zA-Z ]*[a-zA-Z]+[a-zA-Z ]*)";
return "myform.xhtml";
}
}
myform.xhtml With bean class variable for regex pattern
<p:inputText id="name" value="#{categoryBean.selectedCategory.name}">
<f:validateRegex for="name" pattern="#{categeoryBean.categoryNamePattern}"/>
</p:inputText>
myform.xhtml This Works fine with pattern defined inside
<p:inputText id="name" value="#{categoryBean.selectedCategory.name}">
<f:validateRegex for="name" pattern="([a-zA-Z ]*[a-zA-Z]+[a-zA-Z ]*)"/>
</p:inputText>
Finally I did with validator tag. wrote a new validator method
This works fine.
#Service
class CategoryBean {
String catNamePattern;
String showForm(){
categoryNamePattern = "([a-zA-Z ]*[a-zA-Z]+[a-zA-Z ]*)";
return "myform.xhtml";
}
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
if (catNamePattern != null) {
RegexValidator regexValidator = new RegexValidator();
regexValidator.setPattern(categoryNamePattern);
regexValidator.validate(context, component, value);
}
}
}
<p:inputText id="name" value="#{categoryBean.selectedCategory.name}">
<f:validateRegex for="name" pattern="#{categeoryBean.categoryNamePattern}" validator="#{categoryBean.validate}" />
</p:inputText>
I'm creating a registration form. I want to force that p:password is strong. Is there any way to validate that p:password is strong? I want to be taken as 'strong' the same indicator of p:password's feedback.
My solution for this:
<h:form id="form" >
<p:password value="#{regitroCtrl.usuario.contrasenia}"
id="contrasena"
feedback="true"
required="true"
onblur="validarPassword()"/>
<p:message for="contrasena" id="contrasenaMsg" />
<p:commandButton value="Registrarse"
action="#{regitroCtrl.registrarse()}"
update="form"
onclick="return validarPassword()"/>
</h:form>
The validarPassword function:
function validarPassword(){
var strength = PrimeFaces.widget.Password.prototype.testStrength($("#form\\:contrasena").val());
if(strength <= 30){
$("#form\\:contrasenaMsg").html('<span class="ui-message-error-icon"></span><span class="ui-message-error-detail">Por favor, ingresa una contraseña más fuerte</span>');
$("#form\\:contrasena").addClass("ui-state-error");
return false;
}
else {
$("#form\\:contrasenaMsg").html('');
$("#form\\:contrasena").removeClass("ui-state-error");
return true;
}
}
Seems there is no build-in solution for your requirement. Only I can see it in primefaces showcase is password feed back
<p:password id="pwd" value="#{passwordView.password3}" feedback="true"
weakLabel="Weak" goodLabel="Good" strongLabel="Strong"/>
Alternately you can use validator
<p:password id="pwd" value="#{passwordView.password3}" feedback="true"
weakLabel="Weak" goodLabel="Good" strongLabel="Strong">
<f:validateLength minimum="4" maximum="101"/> // or
<f:validator validatorId="passwordValidator" />
</p:password>
Validation class
#ManagedBean
#RequestScoped
#FacesValidator(value = "passwordValidator")
public class PasswordValidator implements Validator, Serializable {
#Override
public void validate(FacesContext fc, UIComponent uic, Object propertyValue) throws ValidatorException {
// your validation here
}
I have a very strange problem with JSF, but I cannot solve it on my own, because there is no error message I can google for. The problem is, that I have one view for submitting a new article or updating an existing article.
The method getArticle() returns - if ?id=x is set via url - the article POJO with the id of x. Otherwise a pure empty new article. Depending of id is set, the mode editArticle is set to true or false.
So if I pass an id via URL, the form changes to "Update article" and the values of the article are shown. But if I hit the submit button, nothing happens. No output, no error. Using HTTP Live Headers in Firefox, I see a request to the server. Looking with wireshark on the loopback interface, there is traffic, too.
But on the other hand, the "Create new article"-Button (if id is not set) without a problem.
The environment: JSF 2.2, Apache Tomcat 7/8, Java 7/8, Windows/Ubuntu (tried different envs, but always the same, so it seems to be a problem "by design" :-) ). Tried also renaming methods, calling via ActionListener, changing the order of the panelGrids... but no way. The method updateArticle() of the bean is never called by hitting the button.
<h:form id="idMasterForm" enctype="multipart/form-data">
<h:panelGroup rendered="#{userController.loggedIn}">
<h:panelGrid columns="2" cellpadding="5">
<p:outputLabel for="title" value="Title" />
<p:inputMask id="title"
value="#{editArticleController.article.title}" />
<p:outputLabel for="author" value="Author" />
<p:inputText id="author" value="#{userController.id}"
readonly="true" />
<p:outputLabel for="date" value="Date" />
<p:inputMask id="date"
value="#{editArticleController.article.date}" readonly="true" />
<p:outputLabel for="link" value="File" />
<p:selectOneMenu id="link"
value="#{editArticleController.article.link}">
<f:selectItems value="#{uploadFilesController.filesItems}" />
</p:selectOneMenu>
<p:outputLabel for="editor" value="" />
<p:editor id="editor" widgetVar="editorWidget"
value="#{editArticleController.article.text}" width="600" />
</h:panelGrid>
<h:panelGrid columns="2" style="margin-top: 10px" rendered="#{!editArticleController.editArticle}">
<p:commandButton value="Submit new article"
action="#{editArticleController.createArticle()}"
icon="ui-icon-disk" />
<p:commandButton value="Clear" type="button"
onclick="PF('editorWidget').clear();" icon="ui-icon-close" />
</h:panelGrid>
<h:panelGrid columns="2" style="margin-top: 10px" rendered="#{editArticleController.editArticle}" >
<p:commandButton value="Update article"
action="#{editArticleController.updateArticle()}"
icon="ui-icon-disk" />
<p:commandButton value="Clear" type="button"
onclick="PF('editorWidget').clear();" icon="ui-icon-close" />
</h:panelGrid>
<h:outputText rendered="#{ ! userController.loggedIn}"
value="#{res.globNotLoggedIn}" />
</h:panelGroup>
</h:form>
And here is the Managed Bean:
import java.util.Date;
import javax.faces.bean.ManagedBean;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import hwr.Util;
import hwr.g2.model.Archive;
import hwr.g2.model.Article;
import hwr.g2.model.Author;
import hwr.user.UserController;
#ManagedBean
public class EditArticleController {
private Article article;
private Boolean editArticle;
private Integer editArticleID;
public EditArticleController() {
this.article = new Article();
System.out.println("EditArticleController was called");
}
public Article getArticle() {
//System.out.println("getArticle() was called");
if (this.getEditArticle()) {
this.article = new Article(this.editArticleID);
}
return this.article;
}
public void setArticle(Integer articleID) {
this.article = new Article(articleID);
}
public void setArticle(Article article) {
System.out.println("setArticle(Article article) was called");
this.article = article;
}
public void setText(String text) {
this.article.setText(text);
}
public String getText() {
return this.article.getText();
}
public void setTitle(String title) {
this.article.setTitle(title);
}
public String getTitle() {
return this.article.getTitle();
}
public Boolean getEditArticle() {
// https://stackoverflow.com/questions/550448/get-request-and-session-parameters-and-attributes-from-jsf-pages
HttpServletRequest req = (HttpServletRequest) FacesContext
.getCurrentInstance().getExternalContext().getRequest();
try {
this.editArticleID = Integer.valueOf(req.getParameter("id"));
if (this.editArticleID > 0) {
this.setEditArticle(true);
} else {
this.setEditArticle(false);
}
} catch (Exception e) {
this.setEditArticle(false);
}
return editArticle;
}
public void setEditArticle(Boolean editArticle) {
this.editArticle = editArticle;
}
public Date getActualDate() {
Date d = new Date();
return d;
}
public void rangChanged() {
// nothing
}
public String createArticle() {
System.out.println("New Article...");
Util util = new Util();
UserController user = (UserController) util.getBean("userController");
this.article.setAuthor(new Author(user.getId()));
this.article.setDate(new Date());
try {
Archive archive = new Archive();
archive.addArticle(this.article);
} catch (Exception e) {
System.out.println("something goes wrong here...");
e.printStackTrace();
}
return "g2_home?faces-redirect=true";
}
public String updateArticle() {
System.out.println("*** Update Article... ***");
System.out.println("Debug: Update article, ID "
+ this.article.getId() + "! title: " + this.article.getTitle()
+ " and text: " + this.article.getText()
+ " and written by "
+ this.article.getAuthor().getFirst());
try {
Archive archive = new Archive();
archive.updateArticle(this.article);
} catch (Exception e) {
System.out.println("something goes wrong here...");
e.printStackTrace();
}
return "g2_home?faces-redirect=true";
}
}
I used a checklist of BalusC (action method is not called in JSF), but didn't found something.
It whould be really great, if someone can point me in the right direction. By the way, is there an better way to fill the form? In my kind of way, the method getArticle() is called several times by the view.
I Think you should define the managed bean scope #ViewScoped or any other scope you want .
look at this question [question] : What is the default Managed Bean Scope in a JSF 2 application?
If you don't set the scope for the bean, it will be #RequestScoped by default, which means the bean will be re created per user request. Change it to #ViewScoped at least in order for the bean to keep alive while the user is interacting with the same view in multiple requests (e.g. ajax requests).
#ManagedBean
#ViewScoped
public class EditArticleController {
//rest of class definition
}
I try learn JSF and faced with problem.
I did use Servlet 2.5, JDK 1.6 and JSF 2.0.6 (com.sun.faces version from pom file).
I have a simple JSF page that has a <h:inputText/> tag for interaction with user
I expect what user fill this h:inputText then click on h:commandButton and on server side i will get backing bean with updated value.
But in my case lifecycle of JSF breaks on process validations, move to render
response and show to user "Parser error!" message
I.e. for simple h:inputText without any validator and converter i receive error message from server side about parsing of h:inputText value.
After some time i figured out what i can create my own converter which will not modify object, just pass String through himself.
I did add my realization of converter to <h:inputText/> and this work.
Question:
In all examples in books and other tutorials nobody used custom converter for <h:inputText/> if inputText is representation of String value of backing bean.
Why all of this tutorials and examples not working for me without custom converter? Where my mistake?
Source codes:
index.xhtml without converter, not worked for me:
<h:form id="UserForm">
<h:outputText value="Insert your first name:" />
<h:inputText id="userNameID" required="true" value="#{userBean.firstName}">
<f:validateLength minimum="5" maximum="25" />
</h:inputText>
<h:message showSummary="true" showDetail="false" for="userNameID" />
<h:commandButton id="submit" action="/view/validator/response?faces-redirect=true"
value="Submit" />
</h:form>
UserBean.java:
#ManagedBean(name = "userBean")
#SessionScoped
public class UserBean implements Serializable {
private String firstName;
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
MyConverter.java - dummy converter
#FacesConverter(value = "myConverter")
public class MyConverter implements Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
return value;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return value.toString();
}
}
index.xhtml with converter, worked as expected:
<h:form id="UserForm">
<h:outputText value="Insert your first name:" />
<h:inputText id="userNameID" required="true" value="#{userBean.firstName}" converter="myConverter">
<f:validateLength minimum="5" maximum="25" />
</h:inputText>
<h:message showSummary="true" showDetail="false" for="userNameID" />
<h:commandButton id="submit" action="/view/validator/response?faces-redirect=true"
value="Submit" />
</h:form>
The cause of the problem is not visible in the code posted so far, but the key symptom "it fails with a message coming from a so far unidentified converter while it succeeds with an explicit converter" suggests that you've elsewhere in the same project a #FacesConverter(forClass=String.class) which would run automatically on every single String property which doesn't have another converter explicitly specified.