Why Entity bean field (java.util.Date) changes value after an update - jsf

I have this Entity bean "User" that has a java.util.Date field. When I update any of the User's fields on the JSF page (i.e. phone number, company name, etc.) for some odd reason, the value for the date field changes in the database. My development environment is Netbeans 12.0, EclipseLink JPA, Apache Derby DB, and GlassFish 5.1 on Windows 10.
For example when I add a user (Bob) with the date of birth "1980-08-20", the JSF sets the value of "1/20/80 3:38 AM" for Bob's User entity, furthermore, no matter what time of the day, I add the user the "3:38 AM" is the fixed time always appended to the date. Later, when I retrieve Bob from the database and display its info on the JSF page, his date of birth is "1980-08-20" as expected. If I update any field (i.e. phone number) for Bob, the date of birth value of "1/20/80 3:38 AM" sent to the Session Bean LoginRequestSessionBean that handles the update (I verified it through the debugger). After the update is successfully completed and I retrieved Bob from the database and display on the JSF page then the date of birth for Bob is "1/20/80 12:00 AM" instead of "1/20/80 3:38 AM", hence I see "1980-30-19" instead of "1980-08-20"? Any idea?
Here is the SQL log when adding Bob to the system:
INSERT INTO PERSISTENCE_USER (ID, CELLPHONE, COMPANY, DATEOFBIRTH, FIRSTNAME, LASTNAME, OFFICEPHONE, PASSWORD, USERID, USERROLE) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
bind => [5, (910)-509-3924, IBM, 1980-01-20, Bob, Nittelo, (818)-456-9012, password, Bobnitello, consumer]]]
Here is the SQL log when updating Bob
UPDATE PERSISTENCE_USER SET USERROLE = ?, CELLPHONE = ?, DATEOFBIRTH = ?, LASTNAME = ?, USERID = ?, FIRSTNAME = ?, OFFICEPHONE = ?, COMPANY = ? WHERE (ID = ?)
bind => [consumer, (910)-509-3924, 1980-01-20, Nittelo, Bobnitello, Bob, (818)-456-9011, IBM, 5]]]
I have a JSF page that displays all users and allows updates to the user information. There is another JSF page that allows adding users to the system. Here is the source code:
#NamedQuery(
name = "updateUser",
query = "UPDATE User u SET u.userId=?1, u.userRole=?2, u.cellPhone=?3, u.company=?4, "
+ "u.dateOfBirth=?5, u.firstName=?6, u.lastName=?7, u.officePhone=?8 "
+ "WHERE u.id = ?9"
)
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotNull
private String userId;
#NotNull
private String password;
#NotNull
private String userRole;
#NotNull
private String firstName;
#NotNull
private String lastName;
#Temporal(TemporalType.DATE)
private Date dateOfBirth;
#NotNull
private String officePhone;
private String cellPhone;
#NotNull
private String company;
............
}
This is the class interacting with the database
Stateless
public class LoginRequestSessionBean {
public void addUser(User u) throws ListServiceException {
try {
em.persist(u);
} catch (Exception e) {
throw (ExceptionHandler.wrapException(
e, logger,
"Error occured when adding a user "+u.getUserId()));
}
}
public void removeUser(User u) throws ListServiceException{
try{
if(!em.contains(u)){
u = em.merge(u);
}
em.remove(u);
} catch (Exception e) {
throw (ExceptionHandler.wrapException(e, logger,"Error occured while removing a user");
}
}
public void updateUser(User u) throws ListServiceException{
try {
updatedRow = em.createNamedQuery("updateUser")
.setParameter(1, u.getUserId())
.setParameter(2, u.getUserRole())
.setParameter(3, u.getCellPhone())
.setParameter(4, u.getCompany())
.setParameter(5, u.getDateOfBirth())
.setParameter(6, u.getFirstName())
.setParameter(7, u.getLastName())
.setParameter(8, u.getOfficePhone())
.setParameter(9, u.getId())
.executeUpdate();
} catch (Exception e) {
throw ExceptionHandler.wrapException(e, logger, "Error occured while updating user");
}
}
public User getUser(Long id) throws ListServiceException{
User user;
try {
user = em.find(User.class, id);
} catch (Exception e) {
throw ExceptionHandler.wrapException(e,logger,"Error occured in"+className+".getuser()");
}
return user;
}
}
This is the relevant part of the Update JSF page handling the date column
<h:column>
<f:facet name="header">#{bundle.loginmanagementdob}</f:facet>
<h:inputText
p:type="date"
value = "#{l.dateOfBirth}"
size ="15" rendered = "#{l.canUpdate}" >
<f:convertDateTime type="date"
pattern = "yyyy-mm-dd" />
</h:inputText>
<h:outputText value = "#{l.dateOfBirth}"
rendered = "#{not l.canUpdate}" >
<f:convertDateTime
type="date"
pattern = "yyyy-mm-dd" />
</h:outputText>
</h:column>
<h:column>
<f:facet name = "header">Update</f:facet>
<h:commandLink value = "Update"
disabled="#{login.currentUser.userRole == 'delete' or login.currentUser.userRole == 'consumer'}"
action = "#{loginManagment.updateLinkAction(l)}"
rendered = "#{not l.canUpdate}">
</h:commandLink>
</h:column>
<f:facet name="footer">
<h:panelGroup style="display: block; border-color: aquamarine;text-align: center;">
<h:commandButton id="update"
tabindex="1"
value="Save updates"
action="#{loginManagment.saveUpdate}" />
</h:panelGroup>
</f:facet>
This the managed bean for the JSF page:
#Named
#SessionScoped
public class LoginManagment implements Serializable {
private static final long serialVersionUID = 1009L;
private LoginRequestSessionBean request;
private final ResourceBundle bundle; //application resource bundle
public LoginManagment() {
//Get the application's resource bundle
bundle = ResourceBundle.getBundle("webmessages");
}
public List<User> getUsers() {
if ((users == null) || refresh) {
try {
users = request.getUsers();
} catch (EJBException e) {
FacesMessage errMsg = new FacesMessage(e.getMessage());
FacesContext.getCurrentInstance().addMessage(null, errMsg);
}
refresh = false;
}
return users;
}
public void resetUpdateLink() {
users
.stream()
.filter(e -> e.getCanUpdate() == true)
.forEach(e -> e.setCanUpdate(false));
}
public String updateLinkAction(User u) {
u.setCanUpdate(true);
return null;
}
public String saveUpdate() {
Function<User, User> update = n -> {
request.updateUser(n);
return n;
};
try {
users
.stream()
.filter(e -> e.getCanUpdate() == true)
.forEach(update);
resetUpdateLink();
FacesMessage msg = new FacesMessage(bundle.getString("loginmanagementupdatesuccess"));
FacesContext.getCurrentInstance().addMessage(null, msg);
} catch (ListServiceException e) {
FacesMessage errMsg = new FacesMessage(e.getMessage());
FacesContext.getCurrentInstance().addMessage(null, errMsg);
}
logger.exiting(className, "saveUpdate()");
return null;
}
}
Here is the relevant part of the add user JSF page that deals with the Date field:
<h:outputLabel id="adddoblabel"
for="adduserdob"
style="color: green; font: caption; font-size: large;
font-family: cursive; border-color: aquamarine"
value="#{bundle.adduserdob}" />
<h:inputText id="adduserdob"
p:type="date"
label="Date Of Birth "
title="Date Of Birth"
style="border-color: aquamarine"
value="#{addUser.dateOfBirth}"
required="true"
requiredMessage="#{bundle.adduserdoberror}"
maxlength="30" >
<f:convertDateTime type="date"
pattern = "yyyy-mm-dd" />
</h:inputText>
<f:facet name="footer">
<h:panelGroup style="display: block; border-color: aquamarine;text-align: center;">
<h:commandButton id="addusercommandbutton"
value="Add"
immediate="false"
style="font-size: large; font-family: cursive"
action="#{addUser.addAction}">
</h:commandButton>
</h:panelGroup>
</f:facet>
</h:panelGrid>
Here is the managed bean for the JSF add user page:
#Named
#SessionScoped
public class AddUser implements Serializable {
private static final long serialVersionUID = 1100L;
private String firstName;
private String lastName;
private Date dateOfBirth;
#EJB
private LoginRequestSessionBean request;
private ResourceBundle bundle; //application resource bundle
public AddUser() {
bundle = ResourceBundle.getBundle("webmessages");
}
public Date getDateOfBirth() {
return dateOfBirth;
}
public void setDateOfBirth(Date date){
dateOfBirth=date;
}
private void clearDataField() {
this.password = null;
this.userId = null;
this.role = null;
this.cellPhone = null;
this.officePhone = null;
this.company = null;
this.dateOfBirth = null;
this.firstName = null;
this.lastName = null;
}
public void addAction() {
try {
User u = new User(getUserId(), getPassword(), getRole(), getFirstName(), getLastName()
,getDateOfBirth(), getOfficePhone(),getCellPhone(),getCompany());
request.addUser(u);
clearDataField();
FacesMessage successMsg = new FacesMessage(bundle.getString("addusersuccess"));
FacesContext.getCurrentInstance().addMessage(null, successMsg);
} catch (EJBException e) {
FacesMessage successMsg = new FacesMessage(e.getMessage());
FacesContext.getCurrentInstance().addMessage(null, successMsg);
}
}
}

It's because you've configured the date converter to interpret the part between hyphens as minutes.
<f:convertDateTime type="date" pattern="yyyy-mm-dd" />
According to its documentation the pattern symbols are specified in the documentation of java.text.SimpleDateFormat. This documentation says that you should be using M for months.
Letter
Date or time component
Presentation
Examples
M
Month in year (context sensitive)
Month
July; Jul; 07
m
Minute in hour
Number
30
So, adjust the pattern accordingly:
<f:convertDateTime type="date" pattern="yyyy-MM-dd" />
Unrelated to the concrete problem: the type attribute is ignored when the pattern attribute is specified. The below declaration is equally fine.
<f:convertDateTime pattern="yyyy-MM-dd" />
This is also specified in its documentation.
If a pattern has been specified, its syntax must conform the rules specified by java.text.SimpleDateFormat. Such a pattern will be used to parse, and the type, dateStyle, and timeStyle properties will be ignored.

Related

How to make search result like Google in JSF?

So, I want to display search result as I type the keyword and change the color of the search result text in JSF like when you use Google to search.
Search example (WhatsApp)
I've done the keyup part but still wonder how to apply highlight text using javascript in JSF.
Here is my xhtml code
<h:form>
<h:outputLabel value="Keyword "/>
<h:inputText id="key" value="#{bookList.keyword}" style="height: 22px">
<f:ajax event="keyup" render="search"/>
</h:inputText>
<h:commandButton value="SEARCH" action="index" styleClass="buttonSearch"/>
</h:form>
<br/>
<h:dataTable value="#{bookList.books}" var="book" id="search"
class="book-table"
headerClass="book-table-header">
<h:column>
#{book.title}
</h:column>
<h:column>
#{book.author}
</h:column>
</h:dataTable>
and this is my java code...
Constructor
public class Book {
private String title;
private String author;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public Book(String title, String author){
this.title = title;
this.author = author;
}
}
Data
#ManagedBean
#RequestScoped
public class BookList {
private String keyword = "";
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
private List<Book> books = new ArrayList<Book>(
Arrays.asList(
new Book("My First Learn to Write Workbook", "Crystal Radke"),
new Book("Where the Crawdads Sing", "Delia Owens"),
new Book("Little Fires Everywhere: A Novel", "Celeste Ng"),
new Book("Fortitude: American Resilience in the Era", "Dan Crenshaw"),
new Book("Arguing the Socialists", "Glenn Beck"),
new Book("Hidden Valley Road: Inside the Mind of an American Family", "Robert Kolker")
)
);
public List<Book> getBooks() {
if (keyword.equals("")) {
return books;
} else {
List<Book> listSearch = new ArrayList<Book>();
for(Book book:books){
if(book.getAuthor().toLowerCase().contains(keyword.toLowerCase())
|| book.getTitle().toLowerCase().contains(keyword.toLowerCase())){
listSearch.add(book);
}
}
return listSearch;
}
}
}
Sorry, if my question isn't nice.

Highlight invalid field when ConstraintValidator fails

I want to ensure that only date values between 1.1.1900 and 31.12.2100 are entered via WebUI. Therefore I created the #Date annotation and the corresponding validator implementation DateValidator.java.
In my entity class the date field is annotated with #Date. Whenever I enter an invalid date value, the default message from the #Date annotation is shown in the global <p:messages .../> but the input field is not marked as invalid, as this is done when an empty value is entered!
When I enter an empty value, the #NotNull validation fails in the PROCESS_VALIDATION phase, the error message is shown, the input field is highlighted and the RENDER_RESPONSE phase is executed next.
In case of an invalid date value, the error message is shown but also UPDATE_MODEL_VALUES, UPDATE_MODEL_VALUES and RENDER_RESPONSE are executed!
Date.java
#Target({ElementType.METHOD,ElementType.FIELD,ElementType.ANNOTATION_TYPE,ElementType.CONSTRUCTOR,ElementType.PARAMETER})
#Retention(value = RetentionPolicy.RUNTIME)
#Constraint(validatedBy = {DateValidator.class})
#Documented
public #interface Date {
String message() default "Invalid Date";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
#Target({ElementType.METHOD,ElementType.FIELD,ElementType.ANNOTATION_TYPE,ElementType.CONSTRUCTOR,ElementType.PARAMETER})
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface List {
Date[] value();
}
}
DateValidator.java
public class DateValidator implements ConstraintValidator<Date, Calendar> {
#Override
public void initialize(Date date) {}
/**
* Returns {#code true}, if Date of Calendar is between 1.1.1900 and 31.12.2100
*
* #param calendar
* #param constraintValidatorContext
* #return
*/
#Override
public boolean isValid(Calendar calendar, ConstraintValidatorContext constraintValidatorContext) {
if (Optional.ofNullable(calendar).isPresent()) {
if (calendar.compareTo(minDate) == -1) {
return false;
}
if (calendar.compareTo(maxDate) == 1) {
return false;
}
}
return true;
}
private static Calendar minDate = new GregorianCalendar(1900, 0, 1);
private static Calendar maxDate = new GregorianCalendar(2100, 11, 31);
}
Entity.java
public class Entity {
private java.util.Calendar date;
#NotNull
#Date
#Temporal(TemporalType.TIMESTAMP)
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = MisEntity.DATETIME_PATTERN)
#Column(name = "date", nullable = false)
public java.util.Calendar getDate() {
return date;
}
}
page.xhtml
<p:messages id="messages" autoUpdate="true" closable="true" showDetail="true"/>
<p:outputLabel for="date" ="#{bundle['date']}"/>
<p:calendar id="date" showButtonPanel="true" showOn="button"
required="true"
value="#{bean.date}"
mask="true" pattern="dd.MM.yyyy HH:mm">
<f:convertDateTime pattern="#{component.pattern}"/>
</p:calendar>
When I implement a FacesValidator and use this validator for the input field, the validation fails on invalid values in PROCESS_VALIDATIONS,
the error message is shown, the invalid field is highlighted and RENDER_RESPONSE is the next phase.
DateValidator2.java
#FacesValidator("my.company.web.validation.DateValidator")
public class DateValidator implements Validator {
#Override
public void validate(FacesContext facesContext, UIComponent uiComponent, Object value) throws ValidatorException {
boolean valid = false;
if (Optional.ofNullable(value).isPresent() && value instanceof Date) {
Calendar calendar = GregorianCalendar.getInstance();
calendar.setTime((Date) value);
valid = calendar.compareTo(minDate) != -1 && calendar.compareTo(maxDate) != 1;
}
if (!valid) {
FacesMessage msg = new FacesMessage("Invalid date");
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(msg);
}
}
private static Calendar minDate = new GregorianCalendar(1900, 0, 1);
private static Calendar maxDate = new GregorianCalendar(2100, 11, 31);
}
page2.xhtml
<p:messages id="messages" autoUpdate="true" closable="true" showDetail="true"/>
<p:outputLabel for="date" ="#{bundle['date']}"/>
<p:calendar id="date" showButtonPanel="true" showOn="button"
required="true"
value="#{bean.date}"
mask="true" pattern="dd.MM.yyyy HH:mm">
<f:convertDateTime pattern="#{component.pattern}"/>
<f:validator validatorId="my.company.web.validation.DateValidator"/>
</p:calendar>
So the question is, how to use a ConstraintValidator that also highlights invalid input fields - it should be possible, because #NotNull does it as expected!
I have a big domain model where I want to annotate each Calendar field with #Date and I do not want to add for each input field the validator using <f:validator validatorId=".."/>

How to manipulate Java List with jsf RequestScope

I'm using JSF 2.2 with RequestScoped managebean. I'd like to update a Java List inside of Customers entity. When submitting, only info in Java List (List<'Phone >) is gone. I don't want to use SessionScoped. Could anyone share some tips or solve this issue?
My codes are shown here.
Customers Entity:
{ ..
#Column(name = "FIRSTNAME")
private String firstname;
#Column(name = "LASTNAME")
private String lastname;
...
#ElementCollection
#CollectionTable(name = "CUSTOMERS_Phone",
joinColumns = #JoinColumn(name = "CUSTOMERS_ID"))
#AttributeOverride(name = "teleNumbers",
column = #Column(name = "PHONE_NUMBER",length=30))
private List<Phone> phone;
..}
JSF Managebean:
#Named(value = "editCustomersBeanService")
#RequestScoped
public class EditCustomersBeanService implements Serializable {
/**
* Creates a new instance of EditCustomersBeanService
*/
#PostConstruct
public void init() {
ctx = FacesContext.getCurrentInstance();
customers =new Customers();
phones = new ArrayList<>();
customers.setPhone(phones);
}
public EditCustomersBeanService() {
}
#Inject
private BusinessSessionCustomers businessSSCustomers;
private int customerId;
private List<Phone> phones;
private Customers customers;
//setter, getter ...
//update to DB
public String updatedCustomers() {
System.out.println("customer Name: " + customers.getFirstname());
System.out.println("customer LastName: " + customers.getLastname());
System.out.print("List of Phones in updatedCustomers: ");
for (Phone ph : customers.getPhone()) {
System.out.print(ph.getPhoneType() + ", " + ph.getTeleNumbers());
}
businessSSCustomers.mergeToDB(customers);
return "customers";
}
..
}
CustomersEdit.xhtml:
<h:form>
...
<label for="Last Name">Last Name</label>
<h:inputText id="lastName" p:placeholder="Last Name"
value="#{editCustomersBeanService.customers.lastname}"/>
<ui:repeat var="phone" value="#{editCustomersBeanService.customers.phone}" varStatus="status">
<label for="phones">Phone: [#{status.index}]</label>
<h:selectOneMenu value="#{phone.phoneType}">
<f:selectItems value="#{editCustomersBeanService.phoneTypeList}"
itemLabel="#{editCustomersBeanService.phoneType}"
itemValue="#{editCustomersBeanService.phoneType}"/>
</h:selectOneMenu>
<h:inputText class=" form-control" value="#{phone.teleNumbers}" />
</ui:repeat>
<h:commandLink value="Save" action="#{editCustomersBeanService.updatedCustomers()}" />
…
</h:form>
Phone.java:
#Embeddable
public class Phone {
public enum PhoneType {
Home, Mobile, Work
}
#Enumerated(EnumType.STRING)
#Column(name = "PHONE_TYPE", length = 10)
private PhoneType phoneType;
#Column(name = "PHONE_NUM", length = 30)
private String teleNumbers;
//setter, getter
..
}

Passing parameters between managedbeans primefaces

I have a problem with my managedbeans. I cannot manage to pass parameters between them. Here is an XHTML snippet. It is basically a form for login. It just sends the parameters to back bean.
<h:outputLabel for="username" value="Kullanıcı Adı: *" />
<p:inputText id="username" value="#{loginBean.username}" required="true" requiredMessage="Kullanıcı adı giriniz.">
<f:validateLength minimum="2" />
</p:inputText>
<p:message for="username" display="icon"/>
<h:outputLabel for="password" value="Şifre: *" />
<p:inputText id="password" value="#{loginBean.password}" required="true" requiredMessage="Şifreyi giriniz!" type="password">
<f:validateLength minimum="2" />
</p:inputText>
<p:message for="password" id="msgPass" display="icon"/>
<f:facet name="footer">
<center>
<p:commandButton id="submit" value="Giriş" icon="ui-icon-check" action="#{loginBean.check}" style="margin:0" update="grid"/>
</center>
</f:facet>
In my backing bean, I am checking whether the user input matches with the database record. If so then I let him enter the system. At the same time, I am taking his full name.
My backbean:
#ManagedBean
#RequestScoped
public class LoginBean {
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getMgs() {
return mgs;
}
public void setMgs(String mgs) {
this.mgs = mgs;
}
public String getFullname() {
return fullname;
}
public void setFullname(String fullname) {
this.fullname = fullname;
}
public String getOriginalURL() {
return originalURL;
}
public void setOriginalURL(String originalURL) {
this.originalURL = originalURL;
}
private String username;
private String password;
private String mgs;
private String fullname;
private String originalURL;
private static Logger log = Logger.getLogger(LoginBean.class.getName());
public String check() throws Exception {
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/projetakip", "root", "");
Statement stmt = con.createStatement();
String md5Pass = md5(password);
String SQL = "select * from users where username='" + username + "' and password='" + md5Pass + "'";
ResultSet rs = stmt.executeQuery(SQL);
while (rs.next()) {
if (username.matches(rs.getString("username")) && md5Pass.matches(rs.getString("password"))) {
this.fullname = rs.getString("ad") + " " + rs.getString("soyad");
return "panel?faces-redirect=true";
} else {
FacesMessage msg = new FacesMessage("Yanlış kullanıcı adı/şifre.");
FacesContext.getCurrentInstance().addMessage(null, msg);
return "index?faces-redirect=true";
}
}
return "index?faces-redirect=true";
}
public void getProductSetupData(ActionEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
Data data = context.getApplication().evaluateExpressionGet(context, "#{data}", Data.class);
}
What I want is to pass fullName to other beans (or pages). How can I pass this variable between my beans?
Thanks in advance.
BalusC wrote a whole blog post about communication in JSF 2.0, it is truly worthy of your time. Reading it, you will discover that there are more than one way of doing it, one of them being injecting the property itself, in your other beans:
#ManagedProperty("#{loginBean.fullName}")
private String fullName;
And another, perhaps more appropriate, could be to inject the bean itself:
#ManagedProperty("#{loginBean}")
private LoginBean loginBean;

Conversion Error setting value "UserID" for 'null Converter'

I getting a Conversion Error when try delete or edit a user from a table in my application. The value is being passed in the metadata from the listUser.xhmtl to the deleteUser.xhtml page. The value is being passed in the metadata but for some reason upon calling the delete action I get the Conversion Error setting value "someemail#somedomain.com" for 'null Converter'. The user id is a String.
This is the url after requesting the userDelete.xhmtl:
http://localhost:8080/lavpWebApp/user/deleteUser.xhtml?user=someemail%40somedomain.com
This is the userList.xhmtl simplified:
<h:column>
<f:facet name="header">Edit</f:facet>
<h:link outcome="/user/editUser.xhtml" value="Edit User">
<f:param name="user" value="#{item.email}"/>
</h:link>
</h:column>
<h:column>
<f:facet name="header">Delete</f:facet>
<h:link outcome="/user/deleteUser.xhtml" value="Delete User">
<f:param name="user" value="#{item.email}"/>
</h:link>
</h:column>
This is userDelete.xhtml simplified:
<f:metadata>
<f:viewParam name="user" value="#{userController.user}" converter="#{userConverter}"/>
</f:metadata>
<h:body>
Do you want to delete #{userController.user.name}?
<h:form>
<h:commandButton action="#{userController.deleteUser()}"
value="Delete"/>
<h:commandButton action="#{userController.doCancelDeleteUser()}"
value ="Cancel"/>
</h:form>
</h:body>
This is the Converter class:
#ManagedBean
#FacesConverter(value="userConverter")
public class UserConverter implements Converter{
#EJB
private UserSellerEJB userEjb;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null || value.isEmpty())
{
return null;
}
if(!value.matches("\\d+"))
{
throw new ConverterException("The value is not a valid email: " + value);
}
String id = value.toString();
return userEjb.findUserById(id);
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if(value == null)
{
return null;
}
if(!(value instanceof UserSeller))
{
throw new ConverterException("The value is not a User: " + value);
}
String id = ((UserSeller) value).getEmail();
return (id != null) ? id.toString() : null;
}
}
This is the userController class simplified:
#Named
#RequestScoped
public class UserController{
#EJB
private UserSellerEJB userEJB;
private UserSeller user = new UserSeller();
private List<UserSeller> usersList = new ArrayList<UserSeller>();
// ------------------------------------------------------------- Constructor
public UserController() {
}
// -------------------------------------------------------- Business Methods
public String doCreateUser()
{
user = userEJB.createSeller(user);
usersList = userEJB.findAllSellers();
return "listUser?faces-redirect=true";
}
// update user
public void PreRenderView()
{
if(user == null)
{
user = new UserSeller();
}
}
public String doUpdateUser()
{
if(user.getEmail() != null)
{
userEJB.updateSeller(user);
}
else
{
userEJB.createSeller(user);
}
return "listUser?faces-redirect=true";
}
public String deleteUser()
{
userEJB.deleteSeller(user);
return "listUser?faces-redirect=true";
}
public String doCancelDeleteUser()
{
return "listUser?faces-redirect=true";
}
#PostConstruct
public void init()
{
usersList = userEJB.findAllSellers();
}
The null converter in the exception message indicates that the converter instance cannot be found. Since you're referencing the converter as a managed bean by converter="#{userConverter}, it would only be found if it's annotated with #javax.faces.bean.ManagedBean and if the class is located in the WAR (and thus not in the EJB/EAR or elsewhere!).
The #FacesConverter annotation isn't been used in this construct and in fact superfluous — and only confusing to starters. Remove that annotation. The #EJB works indeed only in managed beans.
If really in vain (I could however not explain why), try managing it by CDI instead: replace the JSF #ManagedBean annotation by the CDI #Named annotation. You're apparently already successfully managing front controller beans by CDI.
Unrelated to the concrete problem, the converter seems to be designed to convert based on a technical ID (a DB primary key), not an email address. An email address can never match \d+ (which is regex for "digits only"). Make sure that you're not confusing email address with ID.

Resources