Why do I need the @Valid tag?
chane Feb 18, 2006 2:48 AMI generated a sample CRUD application using the Hibernate Reverse Eng. tool. Worked like a charm - very nice work.
I am trying to do something similar to the example.issue....IssueFinderBean with the property example. For some reason, I can't seem to make it work without the @Valid tag.
When I add a property to the generated SFSB, I must add the @Valid tag to the property. If this tag is not added, and I hit the create button, the request is submitted but returns to the create screen and does not execute the create method on the SFSB (no exception thrown).
The property I am adding is an instance of a second entity bean - although it is not being persisted to the db - I am using it to hold a value to use in a search query.
Is the @Valid tag required? I thought this was only used to indicate Hib Validator should be run on the property.
Thoughts on what I am doing wrong.
Thanks,
Chris....
Seam Beta 2
Jboss 4.0.4
Hib Tools Nightly 2/17/06
Here is the code that was generated and I am modifying slightly:
There are two objects: Person, Sale (included below)
The SFSB is:
package com.its;
// Generated Feb 17, 2006 6:06:18 PM by Hibernate Tools 3.1.0.beta4
import java.util.ResourceBundle;
import javax.ejb.Interceptors;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.ejb.TransactionAttribute;
import static javax.ejb.TransactionAttributeType.NOT_SUPPORTED;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.persistence.EntityManager;
import org.hibernate.validator.Valid;
import org.jboss.seam.Component;
import org.jboss.seam.InterceptionType;
import static org.jboss.seam.ScopeType.CONVERSATION;
import org.jboss.seam.annotations.Begin;
import org.jboss.seam.annotations.Destroy;
import org.jboss.seam.annotations.End;
import org.jboss.seam.annotations.IfInvalid;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Intercept;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.Outcome;
import org.jboss.seam.ejb.SeamInterceptor;
@Name("saleEditor")
@Stateful
@Interceptors(SeamInterceptor.class)
public class SaleEditorBean implements SaleEditor{
@In(create = true)
private EntityManager entityManager;
@Valid
private Sale instance = new Sale();
@TransactionAttribute(NOT_SUPPORTED)
public Sale getInstance(){
return instance;
}
public void setInstance(Sale instance){
this.instance = instance;
}
@Valid
Person myBillToPerson = new Person(); // <- This is the property I am adding
public Person getMyBillToPerson(){
return myBillToPerson;
}
public void setMyBillToPerson(Person myBillToPerson){
this.myBillToPerson = myBillToPerson;
}
private boolean isNew = true;
@TransactionAttribute(NOT_SUPPORTED)
public boolean isNew(){
return isNew;
}
public void setNew(boolean isNew){
this.isNew = isNew;
}
private String doneOutcome = "find";
public void setDoneOutcome(String outcome){
doneOutcome = outcome;
}
@In(required = false)
private transient SaleFinder saleFinder;
@In
private transient ResourceBundle resourceBundle;
@Begin(join = true)
@IfInvalid(outcome = Outcome.REDISPLAY)
public String create(){
if(entityManager.find(Sale.class, instance.getId()) != null) {
FacesContext.getCurrentInstance().addMessage(
null,
new FacesMessage(resourceBundle.getString("Sale_id") + " "
+ resourceBundle.getString("AlreadyExists")));
return null;
}
entityManager.persist(instance);
isNew = false;
refreshFinder();
FacesContext.getCurrentInstance().addMessage( // <- modified to see if I get here
null,
new FacesMessage("made it here"));
return null;
// return "editSale";
}
@IfInvalid(outcome = Outcome.REDISPLAY)
public String update(){
refreshFinder();
return null;
}
@End(ifOutcome = "find")
public String delete(){
entityManager.remove(instance);
instance.getPerson().getSales().remove(instance);
refreshFinder();
return doneOutcome;
}
@End(ifOutcome = "find")
public String done(){
if(!isNew)
entityManager.refresh(instance);
return doneOutcome;
}
private void refreshFinder(){
if(saleFinder != null)
saleFinder.refresh();
}
@Destroy
@Remove
public void destroy(){
}
@In(create = true)
private transient PersonEditor personEditor;
public String person(){
personEditor.setNew(false);
personEditor.setInstance(instance.getPerson());
personEditor.setDoneOutcome("editSale");
return "editPerson";
}
@Begin(join = true)
public String selectPerson(){
CONVERSATION.getContext().set("personSelector",
Component.getInstance("salePersonSelector", true));
return "selectPerson";
}
}
And the page I am modifying:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<f:view>
<f:loadBundle basename="messages" var="msg"/>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>
<h:outputText value="#{msg.Create} #{msg.Sale}" rendered="#{saleEditor.new}"/>
<h:outputText value="#{msg.Update}/#{msg.Delete} #{msg.Sale}" rendered="#{!saleEditor.new}"/>
</title>
<style type="text/css" media="all">
@import "style/default/screen.css";
</style>
</head>
<body>
<h:form>
<h1>
<h:outputText value="#{msg.Create} #{msg.Sale}" rendered="#{saleEditor.new}"/>
<h:outputText value="#{msg.Update}/#{msg.Delete} #{msg.Sale}" rendered="#{!saleEditor.new}"/>
</h1>
<div class="rvgSwitch">
<h:selectOneMenu value="#{switcher.conversationIdOrOutcome}">
<f:selectItem itemLabel="Create Sale" itemValue="editSale"/>
<f:selectItem itemLabel="Create Person" itemValue="editPerson"/>
<f:selectItem itemLabel="Find Sale" itemValue="findSale"/>
<f:selectItem itemLabel="Find Person" itemValue="findPerson"/>
<f:selectItems value="#{switcher.selectItems}"/>
</h:selectOneMenu>
<h:commandButton action="#{switcher.select}" value="Switch"/>
</div>
<div class="rvgFind">
<fieldset class="rvgFieldSet">
<legend><h:outputText value="#{msg.Sale} #{msg.Attributes}"/></legend>
<span class="rvgInputs">
<span class="rvgMessage"><h:messages globalOnly="true"/></span>
<h:outputLabel value="#{msg.Sale_id}" for="xxxx">
<h:inputText value="#{saleEditor.instance.id}" id="xxxx" disabled="#{!saleEditor.new}"/>
<span class="rvgMessage"><h:message for="xxxx"/></span>
</h:outputLabel>
<h:outputLabel value="#{msg.Sale_orderdate}" for="orderdate">
<h:inputText value="#{saleEditor.instance.orderdate}" id="orderdate">
<f:convertDateTime type="both" dateStyle="short"/>
</h:inputText>
<span class="rvgMessage"><h:message for="orderdate"/></span>
</h:outputLabel>
<h:outputLabel value="#{msg.Sale_person}" for="aaa">
<h:inputText value="#{saleEditor.myBillToPerson.id}" id="aaa"/> <!-- here is the input box I added
</h:outputLabel>
<h:outputLabel value="#{msg.Sale_shipTo}" for="shipTo">
<h:inputText value="#{saleEditor.instance.shipTo}" id="shipTo"/>
<span class="rvgMessage"><h:message for="shipTo"/></span>
</h:outputLabel>
</span>
<span class="rvgActions">
<h:commandButton type="submit" value="#{msg.Create}" action="#{saleEditor.create}" rendered="#{saleEditor.new}"/>
<h:commandButton type="submit" value="#{msg.Update}" action="#{saleEditor.update}" rendered="#{!saleEditor.new}"/>
<h:commandButton type="submit" value="#{msg.Delete}" action="#{saleEditor.delete}" rendered="#{!saleEditor.new}"/>
<h:commandButton type="submit" value="#{msg.Done}" action="#{saleEditor.done}"/>
</span>
</fieldset>
</div>
<div class="rvgResults">
<h2><h:outputText value="#{msg.Sale_person}"/></h2>
<h:outputText value="#{msg.No} #{msg.Sale_person}" rendered="#{saleEditor.instance.person == null}"/>
<h:dataTable var="parent" value="#{saleEditor.instance.person}"
rendered="#{saleEditor.instance.person != null}" rowClasses="rvgRowOne,rvgRowTwo">
<h:column>
<f:facet name="header"><h:outputText value="#{msg.Person_id}"/></f:facet>
<h:outputText value="#{parent.id}"/>
</h:column>
<h:column>
<f:facet name="header"><h:outputText value="#{msg.Person_fname}"/></f:facet>
<h:outputText value="#{parent.fname}"/>
</h:column>
<h:column>
<f:facet name="header"><h:outputText value="#{msg.Action}"/></f:facet>
<h:commandButton action="#{saleEditor.person}" value="#{msg.View} #{msg.Person}"/>
</h:column>
</h:dataTable>
<span class="rvgPage">
<h:commandButton type="submit" value="#{msg.Select} #{msg.Person}" action="#{saleEditor.selectPerson}" />
</span>
</div>
</h:form>
</body>
</f:view>
</html>package com.its;
// Generated Feb 17, 2006 6:06:17 PM by Hibernate Tools 3.1.0.beta4
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
/**
* Sale generated by hbm2java
*/
@Entity
@Table(name = "sale", uniqueConstraints = {})
public class Sale implements java.io.Serializable{
// Fields
private long id;
private Person person;// = new Person();
private Date orderdate;
private Long shipTo;
// Constructors
/** default constructor */
public Sale(){
}
/** minimal constructor */
public Sale(long id){
this.id = id;
}
/** full constructor */
public Sale(long id, Person person, Date orderdate, Long shipTo){
this.id = id;
this.person = person;
this.orderdate = orderdate;
this.shipTo = shipTo;
}
// Property accessors
@Id
@Column(name = "id", unique = true, nullable = false, insertable = true, updatable = true)
public long getId(){
return this.id;
}
public void setId(long id){
this.id = id;
}
@ManyToOne(cascade = {}, fetch = FetchType.LAZY)
@JoinColumn(name = "billTo", unique = false, nullable = true, insertable = true, updatable = true)
public Person getPerson(){
return this.person;
}
public void setPerson(Person person){
this.person = person;
}
@Column(name = "orderdate", unique = false, nullable = true, insertable = true, updatable = true, length = 19)
public Date getOrderdate(){
return this.orderdate;
}
public void setOrderdate(Date orderdate){
this.orderdate = orderdate;
}
@Column(name = "shipTo", unique = false, nullable = true, insertable = true, updatable = true)
public Long getShipTo(){
return this.shipTo;
}
public void setShipTo(Long shipTo){
this.shipTo = shipTo;
}
}
package com.its;
// Generated Feb 17, 2006 6:06:17 PM by Hibernate Tools 3.1.0.beta4
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
/**
* Person generated by hbm2java
*/
@Entity
@Table(name = "person", uniqueConstraints = {})
public class Person implements java.io.Serializable{
// Fields
private long id;
private String fname;
private Set<Sale> sales = new HashSet<Sale>(0);
// Constructors
/** default constructor */
public Person(){
}
/** minimal constructor */
public Person(long id){
this.id = id;
}
/** full constructor */
public Person(long id, String fname, Set<Sale> sales){
this.id = id;
this.fname = fname;
this.sales = sales;
}
// Property accessors
@Id
@Column(name = "id", unique = true, nullable = false, insertable = true, updatable = true)
public long getId(){
return this.id;
}
public void setId(long id){
this.id = id;
}
@Column(name = "fname", unique = false, nullable = true, insertable = true, updatable = true, length = 50)
public String getFname(){
return this.fname;
}
public void setFname(String fname){
this.fname = fname;
}
@OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY, mappedBy = "person")
public Set<Sale> getSales(){
return this.sales;
}
public void setSales(Set<Sale> sales){
this.sales = sales;
}
}