Home > Apex, Visualforce > Getter Method Order and Visualforce Pages

Getter Method Order and Visualforce Pages

August 24th, 2010

I recently had a Visualforce page that was working perfectly for over two years. This thing was solid, a workhorse, one of the most used pages I have ever created. Then one day it stopped working as expected. It wasn’t a big deal really, simply an warning message wasn’t being displayed to the users. All unit tests still passed and I had made no major changes to the code. What the crazy I thought?!? The only thing I may have done at some point in the past was make minor changes to the the layout or updated the page API version.

The way I architected the page from the very first day created a ticking time bomb that would show up two years after the page was created. Enter the world of Visualforce page generation and getter method order. Before I get to the juicy good stuff I’ll briefly explain how Visualforce pages are created…at a very high level.

1) Apex constructor code is run
2) Page generation begins
3) As the page starts to convert Visualforce markup to html it will see certain markup ( {!showWarning} ) on the Visualforce page related to variables in the controlling class
4) The page generation engine will be like, “Yo, controller, what up? Send me the variable showWarning” or “Hey, controla-homie, send me the list of accounts”. This is the GET of a specific variable.
5) The page generation engine can then embed the variable on the page as html output or perhaps use it to determine if pieces of the page should be rendered at all, such as a warning message
6) HTML is then fully created and sent to the browser making the request

Next lets take a little quiz. If you think quizzes are lame (I do) pretend this is a challenge of intellect that if solved will save the world from invading aliens. Ya, that’s a little weird and makes my sound crazier than I thought it would but let’s run with it. Take a look at the the code below. First the page:

<apex:page Controller="GetOrder">
 
	<apex:pageMessage title="Large Account Alert" severity="warning" strength="1" rendered="{!showLargeAcctWarning}"/>
 
	<apex:pageBlock >
		<apex:pageBlockTable value="{!accounts}" var="a">
			<apex:column value="{!a.Name}"/>
			<apex:column value="{!a.Name}"/>
			<apex:column value="{!a.NumberOfEmployees}"/>
		</apex:pageBlockTable>
	</apex:pageBlock>
</apex:page>

And then the class:

public class GetOrder{
 
    public Boolean showLargeAcctWarning {get; set;}
    List<Account> accts;
 
    public List<Account> getAccounts(){
        if(accts == null){
            accts = new List<Account>();
 
            for(Account a : [Select Id, Name, NumberOfEmployees from Account limit 5]){
                accts.add(a);
                if(a.NumberOfEmployees > 5){
                    showLargeAcctWarning = true;
                }
            }
        }
        system.debug(showLargeAcctWarning);
        return accts;
    }
}

Do you see anything wrong? If not, then you are a n00b and I laugh at your n00biness while I sit upon my white stallion. Just kidding, I’ve been working with Visualforce since the beginning and I only recently realized what is wrong with the code above. Not kidding about sitting upon a white stallion though. If you do see a problem you are officially a l337 \/I5U4lf0(3 haxor.

So what is the problem? The page should display a warning message if the Number of Employees is greater than 5, right? Wrong! Well… maybe. You can view the actual page above be clicking here. You will see the warning message is not displayed but the list definitely has accounts with more that 5 employees? What is going on here…..queue the Twilight Zone music (just to be clear, the Twilight ZONE, not the dumb sparkly vampire Twilight), you have just crossed over into the Visualforce Getter Zone, dun dun dunnnn.

Let’s take a look at the debug log to see what is happening. First let’s check the debug statement above to see if the show warning variable is being set to true.

screenhunter_07-aug-24-10-40

Hmm, the variable is definitely being set to true so why isn’t my warning being displayed. Let look a little deeper in to the log. Using the new Apex CSI log lets filter down to our get methods.

screenhunter_08-aug-24-10-42

If we look at this closely we will see the get method for the showLargeAcctWarning is called before the getAccounts methods. So when the page rendering and asks for the show warning variable it is false as it has not yet been set to true because the getAccounts method has not even executed yet.

So how to resolve this issue. Enter our knight in shining armor, the constructor. Rather than letting the page determine the order of get methods lets run them ourselves in the class constructor. When you execute code in the constructor it is guaranteed to run before the page generation process begins. Below is the updated code.

public class GetOrderFix {
 
    public Boolean showLargeAcctWarning{get; set;}
    List<Account> accts;
 
    public GetOrderFix(){ //This is the contructor, same name as class, will run before page generation begins
        getAccounts();
    }
 
    public List<Account> getAccounts(){
        if(accts == null){
            accts = new List<Account>();
 
            for(Account a : [Select Id, Name, NumberOfEmployees from Account limit 5]){
                accts.add(a);
                if(a.NumberOfEmployees > 5){
                    showLargeAcctWarning = true;
                }
            }
        }
        system.debug(showLargeAcctWarning);
        return accts;
    }
}

Now the getAccounts method is will run before page generation begins and when the generation engine asks for the show warning variable it will have a value of true. You can see the fixed paged here.

What can make these types of issues so hard to track down is that the order in which get methods are called have no official or documented process. What seems like minor change to your Visualforce markup could change the order in which get methods are called and this could cause your page to stop working properly. What I have started to do, and is probably a best practice I should have always been doing, is setup all initial variables, lists, etc in the constructor. Do this and it should minify your problems… at least with getter method order.

Categories: Apex, Visualforce
  1. August 24th, 2010 at 10:46 | #1

    Really well explained and I appreciate the description of the forensic process. That kind of investigation would make a really great Dreamforce seminar.

  2. August 24th, 2010 at 10:49 | #2

    Good post. One note on getAccounts() method though. Rather than call getAccounts() twice (once in the constructor and then again from the VF getter), you could have a single property for:

    public List Accounts {get; private set;}

    that gets filled initially by the constructor or a call to method like your “getAccounts” (named differently of course to avoid a conflict). This way you only running the query one time on page load.

    Best Regards,

    Mike

  3. August 24th, 2010 at 11:50 | #3

    Things get even more dicey when you start with components, since the setters related to any attributes you pass to a component do not run until after the constructor runs (and, unlike pages, there is no action method). Best work around I have found is to drop an {init} call into my component and drop a String getInit() method into my component Controller which does all necessary handling (including DML statements).

    Also, I strongly recommend never using uninitialized Booleans since they often do funky things (null_Boolean != ‘fun’)

  4. Peter C
    August 24th, 2010 at 12:03 | #4

    Question – is it more efficient to add the getAccounts() to the constructor, or could you just define an explicit getter method for the showLargeAccountWarning, and then have that getter call the getAccounts() method? That way, you know getaccounts is called before it returns the Boolean value, so it would always be set…?

  5. August 24th, 2010 at 12:33 | #5

    Nice. This sounds like a classic compile-time vs run-time binding quiz, except with “page generation time” instead of “compile time”.

  6. August 24th, 2010 at 13:14 | #6

    @Michael, the method will be called twice but the query will only execute once as it checks to see if the list is null and only proceeds if it is.

    @Peter C, I think this adds a bit to much complexity for my liking. It can easily become a giant spaghetti mess when getters start calling getters.

    There are many different ways to approach this problem. One of the reasons I ran into the problem above was at the time there were no apex properties which can greatly simplify getting and setting. Another solution, and what I would probably do today is something similar to this:

    public class GetOrderFix{
     
    	public Boolean showLargeAcctWarning{get; set;}
    	public List<Account> accts {get; set;}
     
    	public GetOrderFix(){ 
    		buildAcctList();
    	}
     
    	public void buildAcctList(){
    		accts = new List<Account>();
     
    		for(Account a : [Select Id, Name, NumberOfEmployees from Account limit 5]){
    			accts.add(a);
    			if(a.NumberOfEmployees > 5){
    				showLargeAcctWarning = true;
    			}
    		}
    		return accts;
    	}
    }
  7. August 25th, 2010 at 05:21 | #7

    I love these little “features” of Apex and Visualforce. They make developing and debugging fun! Not sure how many hours I’ve wasted tracking down issues like this.

  8. August 25th, 2010 at 07:51 | #8

    Nice post. In your analysis, did you find out anything about when static code runs vs. the constructor?

    For example, just for readability, I often do my variables like this.

    public Boolean someFlag {get; set;} {someFlag = false;}

    It all should run before the page loads and, as long as I don’t depend on the someFlag variable inside the constructor, I should be ok. However, just wondering if you came across any quirks.

  9. Ralph Callaway
    August 25th, 2010 at 08:39 | #9

    Great post. Ahh, the idiosyncrasies of Apex and VisualForce.

    In truth, for any language you should design your getters so that you don’t need to depend on execution order, primarily because execution order bugs are so darn hard to debug, and let’s not start on their tendency to arise and disappear spontaneously!!

    Personally I would:
    1) Take advantage of the fact any time you reference a property (accounts in this case) in your controller it runs the getter method (avoiding any execution order issues)
    2) Keep the show warning logic in it’s own setter method (each function has one purpose which makes it easier to understand)


    public class GetOrderFix {

    // do I have any accounts with more than 5 employees
    public Boolean showLargeAcctWarning {
    get {
    // the getter method for 'accounts' will run when 'accounts' is refererence
    for(Account a : accounts){
    if(a.NumberOfEmployees > 5)
    return true;
    }
    }
    private set;
    }

    public List accounts {
    get {
    if(accounts == null) {
    accounts = [Select Id, Name, NumberOfEmployees from Account limit 5];
    }
    return accounts;
    }
    set;
    }
    }

  10. Stephan Morais
    August 27th, 2010 at 08:30 | #10

    One think to note is that execution order for setters and getters is called out in the docs:

    http://www.salesforce.com/us/developer/docs/pages/index_Left.htm#StartTopic=Content/pages_compref_additional_controller.htm

  11. lodoss118
    August 28th, 2010 at 03:08 | #11

    why not just use

    if(a.NumberOfEmployees > 5){
    ApexPages.addMessage(new ApexMessage(WARNING, ‘OMG’));
    }

  12. November 10th, 2010 at 03:23 | #12

    Hi
    Nice post. I was facing this problem where few things looked like they should work but were not working. This post provides a good insight.

    Also I am curious to know that how come you have made two sites in your developer edition?
    Generally we can make only one site using developer edition. You have prepared two http://tehnrddemos-developer-edition.na7.force.com/getorderfix & http://tehnrddemos-developer-edition.na7.force.com/getorder

  13. November 11th, 2010 at 09:49 | #13

    They are the same site but I did not add anything to the default web address. Those are just the page names.

  14. Paul
    November 12th, 2010 at 15:34 | #14

    How would approach this issue when dealing with reRender? This contructor based approach works perfectly on page loads, but what about as part of AJAX partial page refreshes? You still have no control over getter and setter order.

  15. Paul
    November 12th, 2010 at 15:34 | #15

    sorry for the double post, forgot to check the “notify” box :)