I have two entities and a backing bean in my application. Following, a simplified version of it:
Controller and Models:
class BackingBean {
private List<A> collectionOfA;
private A currentA;
private B currentB;
private String newDescription;
// accessors
public void prepareForUpdate(ActionEvent e) {
currentA = (A) e.getComponent().getAttributes().get("a");
currentB = (B) e.getComponent().getAttributes().get("b");
}
public void save(ActionEvent e) {
// method to save b
b.setName("changing the name");
b.setSomeNumber(2);
b.setDescription(newDescription);
entityManager.merge(b);
}
}
#Entity
class A {
private String name;
#OneToMany
private List<B> bs;
}
#Entity
class B {
private String name;
private String description;
private int someNumber;
}
View:
<div>
<!-- some popup with inputs for updating B -->
<h:inputText value="#{backingBean.currentB}" />
<h:commandLink actionListener="#{backingBean.save}" />
</div>
<ui:repeat value="#{backingBean.collectionOfA}" var="a">
<h:outputText>#{a.name}</h:outputText>
<ui:repeat value="#{a.bs}" var="b">
#{b.name}
#{b.description}
#{b.someNumber}
<h:commandLink actionListener="#{backingBean.prepareForUpdate}">
<f:attribute name="a" value="#{a}" />
<f:attribute name="b" value="#{b}" />
</h:commandLink>
</ui:repeat>
</ui:repeat>
Assuming that, when I click the commandLink for prepareForUpdate(), the popup shows, my problem is this: when I save the currentB entity, every field of the entity is updated in the view. However, an instant after, the field b.description is rendered again with the old value. When I check the database, the description is, in fact, updated, as it is if I refresh the page.
Any thoughts on why this is happening?
Related
My project is a spring mvc project.In my project i have a domain Technology which has foreign key reference.When i validating on form submit it threw error....For view part(jsp),i using form:select for viewing department in technology.
How can i validate a foreign reference?????
i tried below code
domain
#Entity
#Table(name = "technology")
public class Technology {
private int id;
#NotEmpty
private String name;
#NotEmpty
private Department department;
private Date createdDate;
private boolean isDelete;
}
message.properties
NotEmpty.technology.department=Required!
Technology.jsp
<form:form method="post" action="add-technology"
commandName="technology" id="technologyForm">
<label>Technology Name</label>
<form:input path="name" /><form:errors path="name" class="error"></form:errors>
<br />
<label>Department</label>
<form:select path="department.id">
<form:option value="0" label="Select" />
<form:options items="${departments}" itemValue="id" itemLabel="name" />
</form:select><form:errors path="department" class="error"></form:errors>
<%-- <form:select path="department.id" items="${departments}" /> --%>
<input type="submit" class="btn btn-primary"/>
</form:form>
controller
#RequestMapping(value = "/add-technology")
public String addTechnology(
#ModelAttribute(value = "technology")#Valid Technology technology,
BindingResult result) {
if(result.hasErrors()){
return "/secure/admin/technology";
}
java.util.Date utilDate = new java.util.Date();
Date sqlDate = new Date(utilDate.getTime());
technology.setCreatedDate(sqlDate);
technologyService.saveTechnology(technology);
return "redirect:/technologies";
}
ERROR
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.validation.UnexpectedTypeException: No validator could be found for type: com.company.product.domain.Department
How can i resolve this problem???
Here you have to implement validator for Technology object
class TechnologyValidator extends Validator {
public boolean supports(Class<?> cls) {
return Technology .class.equals(cls);
}
public void validate(Object target, Errors errors) {
super.validate(target, errors);
Technology tecObj= (Technology ) target;
//here i am assuming Technology name is REQUIRED and
//NotEmpty.technology.name is in message.properties
ValidationUtils.rejectIfEmptyOrWhitespace(errors,"name",
"NotEmpty.technology.name");
Department dept = tecObj.getDepartment();
//as from from your are binding department ID
if (dept==null || dept.getId()==null || dept.getId()==0L ) {
errors.rejectValue("department.id", "NotEmpty.technology.department");
}
}
}
And create bean of this class in Spring-context
#Autowired
TechnologyValidator techValid;
And call this validator in your controller like
#RequestMapping(value = "/add-technology")
public String addTechnology(
#ModelAttribute(value = "technology") Technology technology,
BindingResult result) {
//call validator
techValid.validate(technology, result);
if(result.hasErrors()){
return "/secure/admin/technology";
}
java.util.Date utilDate = new java.util.Date();
Date sqlDate = new Date(utilDate.getTime());
technology.setCreatedDate(sqlDate);
technologyService.saveTechnology(technology);
return "redirect:/technologies";
}
This question already has answers here:
Why JSF calls getters multiple times
(9 answers)
How and when should I load the model from database for JSF dataTable
(1 answer)
Method must have signature "String method() ...[etc]..." but has signature "void method()"
(1 answer)
Closed 3 years ago.
I'm really new to JSF, I've been learning it exactly 2 days now. Besides the initial confusion about the concepts, I have issues with eclipse too.
I'm using JSF 2.0 with obviously Eclipse and Tomcat 7.
Firstly, let me describe what I'd want to do: in scope of learning the JSF I want to have a User class, with name, surname, age and Id. Then, I'd like to list pre-defined users and add a submit form. Besides that, there's also a "user detail" option.
Here's my code:
User class:
package com.tutorial;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
#ManagedBean
#RequestScoped
public class User {
private String name;
private String surname;
private int age;
private int id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public User(String name, String surname, int age, int id) {
super();
this.name = name;
this.surname = surname;
this.age = age;
this.id = id;
}
public User(){}
}
Users "bean":
package com.tutorial;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
#ManagedBean
#SessionScoped
public class UsersBean {
private List<User> listOfUsers = new ArrayList<User>();
private String passedParameter;
public UsersBean()
{
listOfUsers.add(new User("Tywin", "Lannister", 60, 1));
listOfUsers.add(new User("Tyrion", "Lannister", 30, 2));
listOfUsers.add(new User("Jaime", "Lannister", 31, 3));
}
public List<User> getAll()
{
System.out.println("Called!");
return listOfUsers;
}
public User getDetails()
{
passedParameter = (String) FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("userID");
int id = Integer.parseInt(passedParameter);
User selected = null;
for (User u : listOfUsers)
{
if (u.getId() == id)
{
selected = u;
}
}
return selected;
}
public void addUser(User u)
{
u.setId(listOfUsers.size()+1);
listOfUsers.add(u);
}
}
users.xml (partial code):
<f:view>
<!-- http://stackoverflow.com/questions/8083469/method-must-have-signature-string-method-etc-but-has-signature-void -->
<h:dataTable value="#{usersBean.all}" var="u">
<h:column>
<f:facet name="header">
User ID
</f:facet>
#{u.id}
</h:column>
<h:column>
<f:facet name="header">
Name
</f:facet>
#{u.name}
</h:column>
<h:column>
<f:facet name="header">
Details
</f:facet>
<h:link outcome="usersDetails" value="get details">
<f:param name="userID" value="#{u.id}"></f:param>
</h:link>
</h:column>
</h:dataTable>
<h:form>
<h:outputText value="Name"></h:outputText>
<h:inputText value="#{user.name}"></h:inputText>
<h:outputText value="Surname"></h:outputText>
<h:inputText value="#{user.surname}"></h:inputText>
<h:outputText value="Age"></h:outputText>
<h:inputText value="#{user.age}"></h:inputText>
<h:commandButton action="#{usersBean.addUser(user)}" value="Add" type="submit"></h:commandButton>
</h:form>
</f:view>
And finally, usersDetails.xhtml (partial code as well):
<ui:define name="content">
<ui:param name="user" value="#{usersBean.details}" />
<h:outputText value="#{user.name}"></h:outputText>
<h:outputText value="#{user.surname}"></h:outputText>
<h:outputText value="#{user.id}"></h:outputText>
</ui:define>
OK, now the questions:
(1) in users.xhtml (see code above - usersBean.all in datatable), it appears as if this function gets called as many times as there are values in arraylist. The "System.out.println("Called!")" is written as many times as there are values in arraylist. Have I done something wrong? I don't believe it's suppose to be called for each object in arraylist.
(2) in users.xhtml, this part of the code
<h:commandButton action="#{usersBean.addUser(user)}" value="Add" type="submit"></h:commandButton>
is highlighted by eclipse and it reads: "Method must have signature "String method(),..."
Did I call the method the wrong way? Is there an alternative to send object to the UsersBean's addUser function? What would be correct way if Eclipse defines this as wrong?
Thank you very much for your time and answers!
1) In JSF, method (used for bulding view) can be called more than once. For proper testing you can create user list with 20 or more users and check again how many times getAll method will be called. I think it still be the same number (3 in your case).
2) Action method in JSF should return redirection outcome (with type String). It is reason why you have message about "signature String method". Change signature of addUser method from public void addUser(User u) to public String addUser(User u) and return outcome for navigation to new page or null for stay on the same page.
I'm working on a project. I need to get a list from MySql database and list it. I'm using JSF 2.1 Primeface 3.5 and Eclipse Juno. I run my code but it doesn't work. You can see my codes in below
//LOGIN CLASS
import parts
#ManagedBean
#SessionScoped
public class Login {
private String username, password;
private PreparedStatement ps, ps2;
private ResultSet rs, rs2;
private List<Application> applications = new ArrayList<Application>();;
private Application selectedApplication;
// GETTERS SETTERS
public String login() {
Connection object = new Connection();
try {
ps = nesne
.getCon()
.prepareStatement(
"select Username, Password from company where Username=? and Password=?");
ps.setString(1, getUsername());
ps.setString(2, getPassword());
rs = ps.executeQuery();
while (rs.next()) {
getList();
return "application";
}
} catch (Exception e) {
System.err.println(e);
}
return "confirm";
}
private List<Application> getList() {
Baglanti nesne = new Baglanti();
try {
ps2 = nesne
.getCon()
.prepareStatement(
"select ApplicationName from application where CompanyID=(select ID from company "
+ "where Username=? and Password=?)");
ps2.setString(1, getUsername());
ps2.setString(2, getPassword());
rs2 = ps2.executeQuery();
while (rs2.next()) {
Application obj = new Application();
obj.setApplicationName(rs2.getString("ApplicationName"));
applications.add(obj);
}
} catch (Exception e) {
System.err.println(e);
}
return applications;
}
APPLICATION CLASS
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class Application {
private int ID;
private int CompanyID;
private String Type;
private Date Date;
private String ApplicationName;
private int CurrentMessageCount;
private int MaxMessage;
private String isPro;
//GETTERS SETTERS
application.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:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Login Confirmed</title>
</h:head>
<h:body>
<h1 class="ui-widget-header ui-corner-all" align="center">Application
List</h1>
<br />
<h:form id="form">
<p:growl id="msgs" showDetail="true" />
<p:dataTable id="applications" var="application"
value="#{login.applications}">
<p:column headerText="Application" style="width:24%">
<h:outputText value="#{login.applications}" />
</p:column>
<p:column style="width:4%">
<p:commandButton id="selectButton" icon="ui-icon-search"
title="View">
<f:setPropertyActionListener value="#{application}"
target="#{login.selectedApplication}" />
</p:commandButton>
</p:column>
</p:dataTable>
</h:form>
I can login properly after that ı saw this page.
Now where is my mistake?
Your var="application" is conflicting with the implicit EL object referring the application context (the ServletContext). You can find here a list of all implicit EL objects. Memorize them. You should never declare an EL variable on exactly those names.
Give it a different name. E.g. var="app", var="_application", etc.
In data table var property mean that every item from database will be accesible as this "var" value. i.e:
You have class Foo:
class Foo{
int number;
String text;
//Setters and getters
}
And another class which handle list of Foo objects (your model as CDI Bean):
#Named
class Boo{
List<Foo> list = new ArrayList<>();
//Getter and setters
}
So to list it all in jsf page you should use it like this:
<p:dataTable id="list" var="listobject" value="#{boo.list}">
<p:column headerText="Number" style="width:24%">
<h:outputText value="#{listobject.number}" />
</p:column>
<p:column headerText="Text" style="width:24%">
<h:outputText value="#{listobject.String}" />
</p:column>
</p:dataTable>
So summary "var" value is accessor string to boo object.
Look also:
PrimeFaces datatable demo and here
Mkyong datatable tutorial
What does it mean that an application is "form based"? I am reading the JSF specification and term turned up.
Form based application, means that for each form, there is a backend bean (java class) that handles the calls to the class.
For instance, you will have a form for login (login.xhtml) and you will present all getter and setters of the values that are needed in the form, in LoginBean.java
All operations (like retrieving data from db) only for this form, will be done in a postconstruct method.
So if login has username and password like this:
<h:inputtext name="name" value="#{loginBean.name}" />
<h:inputtext name="password" value="#{loginBean.password}" />
The LoginBean.java will look:
public class LoginBean{
String name;
String password;
public getName(){return name;}
public getPassword(){return password;}
public setName(String name){
this.name = name;
}
public setPassword(String password){
this.password = password;
}
#PostContruct
public void init(){
this.name = ... //get the name from db
}
}
I discovered a problem in my little program, and Im wondering if anyone have any tips or advice on how to solve this problem as best as possible.
I have the bean testBean which is in request scope. It contains the following:
public class testBean {
private boolean internal = false;
private String input = "";
public String internalTrue() {
System.out.println("Set internal true");
setInternal(true);
return null;
}
public String submitForm() {
System.out.println("");
return null;
}
public boolean isInternal() {
return internal;
}
public void setInternal(boolean internal) {
this.internal = internal;
}
public String getInput() {
return input;
}
public void setInput(String input) {
this.input = input;
}
}
My file welcomeJSF.jsp contains this:
<f:view>
<h:form>
<h:commandButton value="Set internal true" action="#{testBean.internalTrue}" />
</h:form>
<h:panelGrid columns="1" rendered="#{testBean.internal}">
<h:form>
<h:outputText value="JavaServer Faces" /><h:inputText value="#{testBean.input}" />
<h:commandButton value="Go" action="#{testBean.submitForm}" />
</h:form>
</h:panelGrid>
</f:view>
When I run the application Im presented with the button "Set internal true". I click it and Im presented with the form where I have the button "Go". Clicking "Go" does not trigger the method in my bean, most likely because of the field actually not being rendered on the server anymore, and thus it wont run the method. Is there any smart solutions to this?
In advance, thanks for your time.
The children of the panel will never decode input because its rendered attribute always evaluates to false during the APPLY REQUEST VALUES phase. This is a sensible thing to do from a security point of view.
(source: ibm.com)
One thing you could do is take advantage of the fact that JSF components maintain state for the lifetime of the view.
The new bean:
public class TestBean {
private String input = null;
private UIComponent panel;
public String internalTrue() {
panel.setRendered(true);
return null;
}
public String submitForm() {
panel.setRendered(false);
System.out.println("submitForm");
return null;
}
public UIComponent getPanel() { return panel; }
public void setPanel(UIComponent panel) { this.panel = panel; }
public String getInput() { return input; }
public void setInput(String input) { this.input = input; }
}
The new view bound to the bean:
<f:view>
<h:form>
<h:commandButton value="Set internal true"
action="#{testBean.internalTrue}" />
</h:form>
<h:panelGrid binding="#{testBean.panel}" columns="1"
rendered="false">
<h:form>
<h:outputText value="JavaServer Faces" />
<h:inputText value="#{testBean.input}" />
<h:commandButton value="Go" action="#{testBean.submitForm}" />
</h:form>
</h:panelGrid>
</f:view>
Using the binding attribute on the panelGrid will cause setPanel to be called when the view is created/restored.
Note that you may have some testing to do depending on how your implementation's and/or libraries' StateManager stores views between requests (which may in turn be affected by the javax.faces.STATE_SAVING_METHOD init parameter). The view might be stored in a hidden field in the form, in the session keyed to the view ID (which may cause collisions with multiple browser windows), in the session keyed to a unique ID created by a GET or JSF navigation, or by some completely custom mechanism. The pluggable nature of the framework makes it versatile, but in this case it means you need to double-check how your implementation behaves.