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; } }