function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
LaurentDelcLaurentDelc 

Why initialization is called BEFORE my commandAction?

Hi everyone,

 

I am in a visualforce page with a Controller. I have a list and a command button in this page.

 

<apex:selectList id="country" value="{!cdt.Country__c}" size="1"> <apex:selectOptions value="{!Values}"></apex:selectOptions> </apex:selectList><apex:commandButton action="{!test}" value="{!$Label.btn_Save}" />

 

When I call the commandButton, the list method getValues is called BEFORE the test method.

Several questions then:

- why is it called at all? It is part of the initialization of the page and shouldn't be called when we call an action! My intuition is that it is part of the validation that is automatically called by Salesforce when we call an action. But I don't see any reason why

-  It seems that it fires the Heap size verification. And the only solution we found to control the heap size of a page (for example when you want to upload big files) is to put null in the variable holding the big data when you don't need them, which is at the end of the action method. But if this verification is fired BEFORE this action then this solution doesn't work anymore.

 

Any thoughts?

 

Laurent 

 

mulvelingmulveling

I've run up hard against that odd getter behavior. As best I can determine, here's what happens:

  • -> User invokes an action from the Page
  • -> Platform uploads any input data to be submitted for the action, along with the serialized ViewState (which excludes and transient variables), via a POST
  • -> Platform recreates instance of the Controller from the ViewState, transient variables are not restored.
  • -> ??? Platform inexplicably calls certain getter methods reference on the VForce Page ??? I've noticed this with the getter for pageBlockTable components, in particuar. Not terribly surprised it happens with a selectList, too.
  • -> Platform merges the submitted input data from the POST into the Controller state. NOW the controller is in a "valid" state and ready to use.
  • -> Platform calls the method on the Controller that is associated with the action.

 

So, it appears not only can we assume the order of execution of getters on a VForce Pages, we also can't assume that they won't be called immediately preceding an action method, BEFORE the uploaded input data is merged into the Controller state :( Unfortunately I wouldn't count on that behavior changing any time soon. It's a REAL problem in the following circumstances:

  • -> You have a transient variable - "X" - that's "costly" to generate/calculate.
  • -> You made "X" a lazy-loaded transient because it's too big to tote around in the ViewState, but you DO want to keep it in a variable since it's referenced by several getters on a Page, and you don't want to incur the cost of generation more than once per GET/POST request.
  • -> "X" is generated based on input data POST'd as part of an action

 

Is this scenario, with the odd "premature" getter call, "X" gets instantiated in that first getter, except the value is WRONG because the uploaded input data hasn't been merged into the Controller state yet. So, "X" gets instantiated with a state controller state. To work-around this, you could explicitly null out "X" in the first line of the action method (so that it can be instantiated again with the valid state) - since at that point you KNOW the state is valid. However, though the value is now correct, it incurred the cost of instantiation TWICE - once for the premature getter, and once in the action.

If you REALLY have to keep that variable "X" limited to 1 instantiation per request, then you could attempt to track the "state" of the controller, and only perform the lazy-load logic in a non-stale state (returning empty/garbage data otherwise):

  • -> Make a state variable: transient Boolean contollerStateReady = false;
  • -> Set contollerStateReady=true in the Controller constructor, singe a Page GET request does not pose this issue
  • -> Set controllerStateReady=true in the first line of any action methods
  • -> Throw an if(controllerStateReady) guard condition around any lazy-load getter that depends on POST'd input data, returning empty or garbage data in the else clause.

 

I'm not familiar with file uploads in Visualforce yet,but it sounds like the large variable in your case needs to be made a transient (so that it doesn't eat up ViewState space - not familiar with Heap size limit?), possibly with the above caveats thanks to the premature getters.

 

Message Edited by mulveling on 12-09-2009 11:04 AM
Message Edited by mulveling on 12-09-2009 11:06 AM
nathanael.mnathanael.m

I'm definitely seeing the same behaviour.  The getter functions for specific components are being executed in the view state decoding phase of execution. To add to the complication, even if one of those components is set to rendered=false it's still included in the view state. So any of those premature getters are executed on the postback even if the component wasn't rendered.

 

 

It also affects apex:repeat components along with pageBlockTable and selectList as you mentioned.

nathanael.mnathanael.m
I'm going to fully test this theory but it seems that if a getter contains any SOQL queries then the view state decoding phase will execute those getters when constructing the view state.
agrassiagrassi

Any news about this issue? I don't think this is related to SOQL queries within the methods, as I've seen this with plain simple string getters. Maybe it's related to the value being used inside a rerender condition?

agrassiagrassi

So far I've seen this behavior when the getMethods are used inside a "rerender" attribute, or inside the "value" attribute of an <apex:repeat> tag.