Details
-
Type: Improvement
-
Status: Closed
-
Priority: Major
-
Resolution: Fixed
-
Affects Version/s: EE-2.0.0.GA
-
Fix Version/s: 2.1-Beta, EE-2.0.0.GA_P01
-
Component/s: ICE-Components
-
Labels:None
-
Environment:-
-
Assignee Priority:P1
Description
Consider the following source code (BeanA and BeanB source is the same):
@SessionScoped
public class BeanA implements Serializable
{
@PostConstruct
public void init(){
System.out.println("A Created ");
}
public List<String> getA(){
return Arrays.asList("A", "A");
}
}
and the view:
<ice:panelTabSet>
<ice:panelTab label="1">
</ice:panelTab>
<ice:panelTab label="2">
<ice:dataTable value="#{beanB.b}" var="_b">
<ice:column>
<ice:outputText value="#{_b}" />
</ice:column>
</ice:dataTable>
</ice:panelTab>
<ice:panelTab label="3">
<ice:dataTable value="#{beanA.a}" var="_a">
<ice:column>
<ice:outputText value="#{_a}" />
</ice:column>
</ice:dataTable>
</ice:panelTab>
</ice:panelTabSet>
If you navigate to tab 2, the first bean´s init method will be called ("B Created"). Then navigate to tab 3 and you will see the same for A ("A created"). If you swap out the h:dataTable/h:column and replace it with it´s ice equivalents and retry the above test, both B and A are created at the same time when you click on tab 2 (("B Created" & "A Created"). Having all getters called can hurt performance since they may contain expensive logic such as DB accesses, etc..
@SessionScoped
public class BeanA implements Serializable
{
@PostConstruct
public void init(){
System.out.println("A Created ");
}
public List<String> getA(){
return Arrays.asList("A", "A");
}
}
and the view:
<ice:panelTabSet>
<ice:panelTab label="1">
</ice:panelTab>
<ice:panelTab label="2">
<ice:dataTable value="#{beanB.b}" var="_b">
<ice:column>
<ice:outputText value="#{_b}" />
</ice:column>
</ice:dataTable>
</ice:panelTab>
<ice:panelTab label="3">
<ice:dataTable value="#{beanA.a}" var="_a">
<ice:column>
<ice:outputText value="#{_a}" />
</ice:column>
</ice:dataTable>
</ice:panelTab>
</ice:panelTabSet>
If you navigate to tab 2, the first bean´s init method will be called ("B Created"). Then navigate to tab 3 and you will see the same for A ("A created"). If you swap out the h:dataTable/h:column and replace it with it´s ice equivalents and retry the above test, both B and A are created at the same time when you click on tab 2 (("B Created" & "A Created"). Having all getters called can hurt performance since they may contain expensive logic such as DB accesses, etc..
Issue Links
- is duplicated by
-
ICE-7314 Backing bean called on children of non-rendered elements
- Closed
Mark Collette said:
Ok, basically the problem is that we've got an incomplete implementation of visitTree, which assumes that it needs to iterate over the dataTable rows, when it should not since we're only doing state restoration, that causes the side effect of loading the dataTable's DataModel and thus loading the beans. Nils has already solved this in the ACE dataTable by adding this guard:
public boolean visitTree(VisitContext context, VisitCallback callback) {
boolean ret = false;
if (this.isVisitable(context)) {
boolean visitRows = requiresRowIteration(context); // *** Here ***
int savedIndex = -1;
{ // *** Here *** savedIndex = getRowIndex(); setRowIndex(-1); }if (visitRows)
...
if (visitRows) setRowIndex(savedIndex); // *** Here ***
...
}
private boolean requiresRowIteration(VisitContext ctx) {
{ // Use JSF 2.1 hints if available return !ctx.getHints().contains(VisitHint.SKIP_ITERATION); }try
catch (NoSuchFieldError e)
{ FacesContext fctx = FacesContext.getCurrentInstance(); return (!PhaseId.RESTORE_VIEW.equals(fctx.getCurrentPhaseId())); }}