[SalesForce] Standard Controller behavior with not available ids – behavior changed

Question

Do standard controllers no longer throw exceptions if the current user doesn't have access to the passed in id? Has this always been that case or did this just recently change? Hoping to validate this is a regression before contacting support …

Background

Regressions are always funky (hard to go back in time to test), but previously, if a page using a standard controller with an ID that wasn't visible to a user you'd get a Data not available white screen of death. This is important in case you do something like this.

public with sharing MyExt {
  public MyExt(ApexPages.StandardController controller) {
    if(controller.getId() != null) {
      My_Object__c obj = [SELECT Id FROM My_Object__c WHERE Id = :controller.getId()];
    }
  }
}

Previously this code would never execute since we'd get the exception before the constructor run, but with Summer '14 orgs (and Winter '14) this pages now are failing with List has no rows for assignment to SObject.

Note that this is distinct from an invalid id (either not the correct object type, or just plain invalid) which still throws a Id value <blah> is not valid for the My_Object__c standard controller.

Docs

The docs aren't super clear, but seem to imply that this should get an exception since standard controller's run in system mode

If a controller extension extends a standard controller, the logic
from the standard controller doesn’t execute in system mode. Instead,
it executes in user mode, in which the permissions, field-level
security, and sharing rules of the current user apply.

Update

After some further testing it appears that, (1) the constructor gets run regardless of whether an id is visible as long as it's valid, (2) nothing gets run if the id is invalid or wrong object type and an Id value <blah> is not valid for the My_Object__c standard controller error is thrown, (3) the Data Not Available error only occurs if the controller object is referenced directly on the page, i.e. {!My_Object__c.Id}. (4) getters may or may not be processed if id is not visible depending on their position until the first getter call to the core object ({My_Object__c.Id}). Maybe this was always the case?

Best Answer

The standard controller will still throw the same Data Not Available error if you use the getRecord() method. i.e.

public with sharing MyExt {
  public My_Object__c obj;

  public MyExt(ApexPages.StandardController controller) {
     obj = (My_Object__c)controller.getRecord();
  }
}

However, the getId() method throws no error and just returns null. So you're best bet would be to stick with the getRecord() method.

As for the regression, who knows, but as of Winter '15 my org functions this way.