[SalesForce] Accessing Non-Static Variables in Static Methods of a Visualforce Controller

I have a scenario where I have one Vf page called 'myVisualforce' and a custom controller 'myController'. In myController I have some non-static variables for example 'var1' and 'var2' and I have few static methods for example 'stat1', 'stat2' etc. I am calling these stat1 and stat2 in myVisualforce as Javascript Remoting methods. Now I want to use variables var1 and var2 in these static methods.

Now,
1. One solution is to use var1 and var2 in myVisualforce and pass it to these in remoting methods as parameters. This one I don't want to use.
2. What I was thinking is, if we open the myVisualforce page it calls the custom controller myController and constructor is also being called. As constructor is getting called then there should be an instance 'myInstance' created of myController that is being used in myVisualforce. Now my question is HOW TO ACCESS 'myInstance' IN THE CONTROLLER.

Any other solution is also welcome.

Best Answer

The short answer is quite simply, you cannot get to the instance of the Apex class that was invoked on page load. It is gone.

You are bumping up against one of the architectural peculiarities of Apex. Your Apex code runs in the scope of one single transaction. We don't get access to the persistent application runtime state. This is fundamentally different from most other programming languages.

Because of this accessing the instance of the controller that was created during page load is as impossible as me trying to get a kiss from Audrey Hepburn. Never mind that she is in a class way beyond me, but more importantly that instance of human just like the on-page-load instance of your controller class has long since ceased to exist.

When your VF page loads, it is in the context of a transaction. The instantiation of the controller, and execution of any methods is ephemeral and only lasts for the lifetime of that HTTP request/response cycle. By the time your page has rendered at the client everything your class created and worked with is sitting on the heap waiting to be garbage collected.

When your remote action method is invoked, there are no instances of the controller in memory. Not the one on page load, and not any others. Each HTTP request that uses the traditional postback request architecture creates a brand new instance of your controller with the page view state making each new instance pick up where the last left off as non-transient instance variables get passed back and forth from client to server like the baton in a relay.

If you need to get access to some functionality in your controller from a static remote method, then there are some options including:

  1. Instantiate it inside the remote method
  2. Move the logic/data you want into static methods/variables/helpers

Here's an illustration of option 1:

public class MixedController {

    private ApexPages.StandardController pageController ;

    public MixedController(ApexPages.StandardController ctrl){

        pageController = ctrl;

    }

    private String fetchAString(){
        return 'A String';
    }

    @RemoteAction
    public static List<Contact> fetchAccts(Id ctrlId){
        List<Contact> ctList = new List<Contact>();

        Account acct = [SELECT Id, Name, BillingCity from Account where Id = : ctrlId];

        MixedController locCtrl = new MixedController(new ApexPages.StandardController(acct));

        String aString = locCtrl.fetchAString();

        return ctList;
    }

}

The first technique carries some risk. If you were to change some persistent data (like the account record the controller is referencing), the next time your page did a proper postback, the page view state might be out of sync with the database. I'm not certain what would happen, or how the VF framework would resolve that.

Moving your logic into static class members might be more safe, but if you are relying on the page view state (to track progress of your user, for instance) that isn't an option, unless you devise some other strategy such as manually storing state in something like a custom setting or custom object field.

In general I try to avoid mixing static and non-static page patterns. If my page is intended for use in the traditional salesforce browser UI, I don't tend to use Javascript remoting, no matter what the perceived performance gain. On the other hand when building Visualforce for mobile consumption, I normally only use remote action methods.

I realize that not every project will be able to do this. But clearly, the mixing of static and non-static interaction with the controller needs to be approached with caution, and you need a game plan for how to handle the transient/non-transient nature of static remote action calls versus stateful traditional postback calls.

Have a read of the documentation on VF page execution order to understand the traditional postback architecture a little better: