BACKGROUND
I want to build a wizard using Visualforce Components. For this I represent each step as a separate component. Each component has an attribute that represents a controller instance from the containing page:
<apex:attribute name="mainController" type="ContainerController" assignTo="{! controller }" required="true"
description="This is the instance of the main controller." />
I then use the controller instance in components' controllers for shared properties, methods etc.
CODE (VF and APEX)
Container.vfp
<apex:page controller="ContainerController" sidebar="false" showHeader="false">
<apex:form>
<apex:outputPanel layout="block">
<apex:commandButton value="Switch" action="{! switch }"/>
</apex:outputPanel>
<c:elementOne mainController="{! instance }" rendered="{! showOne }"/>
<c:elementTwo mainController="{! instance }" rendered="{! showTwo }"/>
</apex:form>
</apex:page>
ContainerController.apxc
public class ContainerController
{
public Boolean showOne { get; set; }
public Boolean showTwo { get; set; }
public String[] mock { get; set; }
public ContainerController()
{
showOne = true;
showTwo = false;
mock = new List<String>();
for (Integer i=0; i<1000; i++)
mock.add('foo-bar'+i);
}
public ContainerController getInstance() { return this; }
public void switch()
{
showOne = !showOne;
showTwo = !showTwo;
}
}
ElementOne.vfc
<apex:component controller="ElementOneController" allowDML="true">
<apex:attribute name="mainController" type="ContainerController" assignTo="{! controller }" required="true"
description="This is the instance of the main controller." />
<apex:sectionHeader title="Element One" />
</apex:component>
ElementOneController.apxc
public class ElementOneController
{
public ContainerController controller { get; set; }
public ElementOneController(){}
}
ElementTwo.vfc
<apex:component controller="ElementTwoController" allowDML="true">
<apex:attribute name="mainController" type="ContainerController" assignTo="{! controller }" required="true"
description="This is the instance of the main controller." />
<apex:sectionHeader title="Element Two" />
</apex:component>
ElementTwoController.apxc
public class ElementTwoController
{
public ContainerController controller { get; set; }
public ElementTwoController(){}
}
QUESTION
I enabled the Development Mode for my user and opened the /apex/Container
page. When I checked the view state I was surprised to discover that the instance of ContainerController
was duplicated.
Then I pressed the Switch
button on the page, and the size tripled the original 2.75 KB and become 8.31 KB
While the total size is 5.06 KB it seems that the size for the instance of ContainerController was counted once in the total calculation. That's not neat, but at least the total size is correct. That's what I thought...
Nay, when I checked my real real project, the view state calculation was "correct" - it duplicated the size of the same instance several times.
In my understanding when an instance of a object is passed as a parameter in Visualforce Component it's passed by reference which means that only one instance of that object exist. So View State should not contain duplicates of that object.
Does anybody know how an object instance used by apex:attribute is reflected in ViewState?
String stuff = 'a'.repeat(100000);
and see if true viewstate blows up as you move from one component to the next'a'.repeat(100000);
and posted my findings as an answer.