4

I have a XHTML page which on submission goes back to itself.
The backing bean is session scoped. On the redirect to itself the page renders the h:dataable twice and gives me duplicate id error.I can visually see the table being rendered twice as well next to each other.
I releaize that it has some thing to do with the fact that backing bean has a property of faces html table and on return it creates again but whats the solution.

Following is roughly derived from this tutorial from JavaBeat . Only main difference is that my backing bean is Session Scoped.

I also releaize that my question probably does not clears it enough but code should :) here it is

Backing bean

import java.util.ArrayList;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.component.html.HtmlDataTable;
import javax.faces.event.ValueChangeEvent;

import com.example.common.web.bean.BaseBean;

@ManagedBean(name = "registrationBean")
@SessionScoped
public class RegisterationViewManagedBean extends BaseBean {


    private String field;
    private List<Employee> employees;
    private Employee employee;
    private HtmlDataTable htmlDataTable;
    private List<Employee> list = new ArrayList();

    public void setSelected(ValueChangeEvent event) {
        employee = (Employee) htmlDataTable.getRowData();
        list = new ArrayList<Employee>();
        list.add(employee);
    }

    public List<Employee> getEmployees() {
        return employees;
    }

    public void setEmployees(List<Employee> employees) {
        this.employees = employees;
    }

    public HtmlDataTable getHtmlDataTable() {
        return htmlDataTable;
    }

    public void setHtmlDataTable(HtmlDataTable htmlDataTable) {
        this.htmlDataTable = htmlDataTable;
    }

    public Employee getEmployee() {
        return employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    public String dataSubmit() {
        for (Employee employee : this.list) {
            System.out.println(employee.getCity());
            System.out.println(employee.getName());
            System.out.println(employee.getEmpNo());
        }
        return "success";
    }

    public String submit() {
        this.employees = new ArrayList<Employee>();
        Employee employee1 = new Employee();
        employee1.setCity("Bangalore");
        employee1.setEmpNo("1");
        employee1.setName("Krishna");
        Employee employee2 = new Employee();
        employee2.setCity("Bangalore");
        employee2.setEmpNo("2");
        employee2.setName("ShunmugaRaja");
        Employee employee3 = new Employee();
        employee3.setCity("Bangalore");
        employee3.setEmpNo("3");
        employee3.setName("JoyChristy");
        this.employees.add(employee1);
        this.employees.add(employee2);
        this.employees.add(employee3);
        return "success";
    }
}

Xhtml Page

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition 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">



    <ui:define name="body">

        <h:form>
            <h:dataTable var="loc" value="#{registrationBean.employees}"
                binding="#{registrationBean.htmlDataTable}">
                <h:column>
                    <h:selectOneRadio onclick="radioButton(this);"
                        valueChangeListener="#{registrationBean.setSelected}">
                        <f:selectItem itemValue="null" />
                    </h:selectOneRadio>
                </h:column>
                <h:column>
                    <h:outputText value="#{loc.name}" />
                </h:column>
                <h:column>
                    <h:outputText value="#{loc.empNo}" />
                </h:column>
                <h:column>
                    <h:outputText value="#{loc.city}" />
                </h:column>
            </h:dataTable>
            <!-- Summary ends -->
            <div class="submitButtons">
                <h:commandButton id="register" action="#{registrationBean.submit}"
                    value="Perform Some Action" />
            </div>
        </h:form>
    </ui:define>
</ui:composition>

Stack trace

Caused by: java.lang.IllegalStateException: component with duplicate id "j_id397249623_10fed7a7:j_id397249623_10fed7bd:j_id397249623_10fed793" found
    at org.apache.myfaces.view.facelets.DefaultFaceletsStateManagementStrategy.checkIds(DefaultFaceletsStateManagementStrategy.java:784)
    at org.apache.myfaces.view.facelets.DefaultFaceletsStateManagementStrategy.checkIds(DefaultFaceletsStateManagementStrategy.java:800)
    at org.apache.myfaces.view.facelets.DefaultFaceletsStateManagementStrategy.checkIds(DefaultFaceletsStateManagementStrategy.java:800)
    at org.apache.myfaces.view.facelets.DefaultFaceletsStateManagementStrategy.checkIds(DefaultFaceletsStateManagementStrategy.java:800)
    at org.apache.myfaces.view.facelets.DefaultFaceletsStateManagementStrategy.saveView(DefaultFaceletsStateManagementStrategy.java:432)
    at org.apache.myfaces.application.StateManagerImpl.saveView(StateManagerImpl.java:160)
    at org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage.renderView(FaceletViewDeclarationLanguage.java:1554)
    at org.apache.myfaces.application.ViewHandlerImpl.renderView(ViewHandlerImpl.java:281)
    at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:59)
    at org.apache.myfaces.tomahawk.application.ResourceViewHandlerWrapper.renderView(ResourceViewHandlerWrapper.java:93)
    at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:59)
    at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:85)
    at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:239)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:191)

Snap enter image description here

Java Ka Baby
  • 4,880
  • 11
  • 39
  • 51
  • @ Java Ka Baby upvoting i would also like to know the answer. – amod Aug 26 '11 at 05:52
  • 1
    Everything looks fine as far. I'd first exclude the Facelet template composition and MyFaces from being suspect. Test it in a basic `` page without any template includes/definitions/compositions. If that fixes the problem, then you've to show how exactly your page is composed, perhaps you made a Facelet template design mistake. If that is not it, test it with Mojarra instead of MyFaces. If that fixes the problem, report it as bug to MyFaces guys, along with a *complete* SSCCE. – BalusC Aug 26 '11 at 23:59
  • Will try and report back thanks. – Java Ka Baby Aug 27 '11 at 03:00

1 Answers1

8

The problem is you are using a session scoped bean to store a page binding. The first time the page is rendered as expected. The second time, the binding has already a component, so all children is duplicated. The problem cannot be solved changing of JSF implementation (because both has the same code inherited from facelets). Try use two beans, one session scoped and the other one request scoped with the binding.

lu4242
  • 2,318
  • 1
  • 15
  • 15
  • Yes thats my initial judgement too as I said in question but it does seem like implementation issue not happening with Mojarra but need to do more investigation before concluding so have just parked this one on the side for now but will update in a few days. – Java Ka Baby Sep 04 '11 at 21:40
  • I see. MyFaces has an optimization in that part to reduce the time spent to build a view, so it does not check if a component was already created because it suppose that (all bindings should be request scope, right?). The invalid case happens when you open two windows on the same browser for the same view with the session scope binding. In this case one view could corrupt the other one. By that reason, use binding on session scope beans is considered invalid. – lu4242 Sep 05 '11 at 17:14
  • You said "all bindings should be request scope, right?" is it right any documentation stating this.@BalusC do you agree with this statement. – Java Ka Baby Sep 05 '11 at 21:29
  • 1
    See JSF 2.0 spec section 3.1.5 "... It is strongly recommend that application developers place managed beans that are pointed at by component binding expressions in “request” scope, and not any other scope. This is because placing it in session or application scope would require threadsafety, since UIComponent instances depends on running inside of a single thread. There are also potentially negative impacts on memory management when placing a component binding in “session” or “view” scopes. ...". So, the position about this on MyFaces comply with the spec. – lu4242 Sep 06 '11 at 00:44
  • Thanks and well done on getting this one . On a different note if two implementations behave differently one is ought to be wrong.As per your answer I read the specs and you are spot on but just in terms of Myfaces vs Mojorra (forgive the spelling) one should fix it IMHO. – Java Ka Baby Sep 06 '11 at 22:40