PAGE-scoped seam component constructor runs 4 times!
deadlockgr Mar 11, 2010 7:06 PMHi all!
This is a newbie question. I a page using a PAGE-scoped component. I would expect that the constructor of the component to be executed once, upon creation of the page, then the component would be stored in the PAGE context, and everybody would be happy.
But what happens is that my constructor runs 4 times and the @Create method runs 2 times. Why is this happening? If someone could take a look I would be grateful.
Cheers!
The output:
Constructor Constructor @Create Constructor Constructor @Create
The page:
<!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:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:a4j="http://richfaces.org/a4j" xmlns:rich="http://richfaces.org/rich"> <body> <ui:composition template="/WEB-INF/facelets/templates/template.xhtml"> <ui:define name="content"> <a4j:loadScript src="/js/focus.js" /> <h:form prependId="false"> <!-- Hotkeys --> <rich:hotKey key="ctrl+s" handler="$('createButton').click();return false;" /> <h:commandButton action="#{applicantBean.cancelCreateApplicant}" value="#{msgs.back_to_search_results}" immediate="true" /> <br /> <br /> <h:outputText value="#{msgs.create_applicant}" class="page_title" /> <table width="100%"> <tbody> <tr> <td width="20%"><h:outputText value="#{msgs.name}" /></td> <td width="30%"><h:inputText id="applicantName" style="width:100%" value="#{applicantBean.applicant.name}" required="true" requiredMessage="#{val.a_value_is_required}" /></td> <td width="50%"><h:message for="applicantName" styleClass="errorMessage" /></td> </tr> <tr> <td><h:outputText value="#{msgs.email}" /><h:outputText value=" #{msgs.optional_in_parenthesis}" styleClass="optional" /></td> <td><h:inputText id="applicantEmail" style="width:100%" value="#{applicantBean.applicant.receiptEmail}"> <f:validator validatorId="EmailValidator" /> </h:inputText></td> <td><h:message for="applicantEmail" styleClass="errorMessage" /></td> </tr> <tr> <td colspan="2" align="right" valign="middle"> <p><h:commandButton id="createButton" action="#{applicantBean.createApplicant}" value="#{msgs.create}"> </h:commandButton> <h:commandButton action="#{applicantBean.cancelCreateApplicant}" value="#{msgs.cancel}" immediate="true"> </h:commandButton></p> </td> </tr> <tr> <td><h:messages errorClass="errorMessage" infoClass="errorMessage" layout="table" globalOnly="true" showDetail="false" showSummary="true" /></td> </tr> </tbody> </table> </h:form> <script type="text/javascript"> setFocus("#{(focus != null) ? focus : 'applicantName'}"); setHighlight('${highlight}'); </script> </ui:define> </ui:composition> </body> </html>
and the component:
import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.Create; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; /** * Managed bean to handle product instances. * * */ @Name("productBean") @Scope(ScopeType.PAGE) public class ProductBean extends BasePageManagedBean { /** * The logger. */ private final static Logger logger = Logger.getLogger(ProductBean.class); /** * Public field for ad-hoc injection to work. */ @EJB(name = "ProductFacadeService") public ProductFacadeService productFacadeService; private Product product; public ProductBean() { System.out.println("Constructor"); } @Create public void onCreate() { product = new Product(); System.out.println("@Create"); } /** * This method creates a product * * @return the action to be taken */ public Navigation.EditProduct createProduct() { if (!productFacadeService.canCreate(product)) { setMessage("val", "product_name_already_exists", null, FacesMessage.SEVERITY_ERROR, "productName"); return null; } productFacadeService.create(product); if (logger.isTraceEnabled()) { logger.trace("Created product: " + product); } return Navigation.EditProduct.SHOW_APPLICANT_PRODUCT_LIST; } /** * Getter for the product * * @return the product */ public Product getProduct() { return product; } /** * Setter for the product * * @param product * the product to set */ public void setProduct(Product product) { this.product = product; } /** * Setter for the applicant of the product * * @param applicant * the applicant to be set */ public void setApplicant(Applicant applicant) { getProduct().setApplicant(applicant); } /** * Navigation-returning method, returns the action to follow after canceling * creating a product. * * @return the action to be taken */ public Navigation.CreateProduct cancelCreateProduct() { return (Navigation.CreateProduct.SHOW_APPLICANT_PRODUCT_LIST); } }