+ Start a Discussion
KevinShukKevinShuk 

Accessing private sobject fields from a "without sharing" custom visualforce controller

I believe I already have this figured out, but I wasn't able to find definitive instruction on this in the Apex docs nor the boards, so I wanted to post this to hopefully help someone else and to see if anyone can further clarify this. The example code below is contrived and is just to illustrate what I've seen. 

 

First, I have a custom object named My_Object__c with a custom Text field named Private_Field__c. Through field level security, this field is not visible to any profile.

 

Next, I have a custom visualforce controller defined without sharing. To give a very rudimentary example:

 

 

public without sharing class MyObjectController {
     public My_Object__c myObject { get; private set; }  

     public MyObjectController() {
          queryMyObject('a01000000000001');
     }

     public queryMyObject(Id myObjectId) {
          myObject = [select Id, Name, Private_Field__c 
                         from My_Object__c 
                         where Id = :myObjectId];
          System.debug(myObject);
     }
} 

 

 

On my visualforce page, if I access the field directly through the sobject property, the value will not display:

 

<apex:page controller="MyObjectController">
myObject's Private Field Value: {!myObject.Private_Field__c}<br/>
</apex:page>

 

 

When I access the page, it is as though the sharing is once again applied to this field. The merge field yields no value. Looking at debug logs, however, I can see that I'm seeing the value for Private_Field__c in the controller when queryMyObject is called.

 

If I add a property to the controller class to return the field, however, I'm able to access it in the page:

 

 

public without sharing class MyObjectController {
     public My_Object__c myObject { get; private set; }
     String privateField { get { return myObject.Private_Field__c; } } // added this property 

     public MyObjectController() {
          queryMyObject('a01000000000001');
     }

     public queryMyObject(Id myObjectId) {
          myObject = [select Id, Name, Private_Field__c 
                         from My_Object__c 
                         where Id = :myObjectId];
          System.debug(myObject);
     }
} 

 Accessing the field property instead of accessing the field directly from the sobject property works:

 

 

<apex:page controller="MyObjectController">
myObject's Private Field Value (direct access): {!myObject.Private_Field__c} (this still won't work)<br/>
myObject's Private Field Value (property access): {!privateField} (this works!)<br/>
</apex:page>

 

My questions here are:

 

Is this documented anywhere? I couldn't find explanation of this specific behavior in the apex code dev guide or the visualforce dev guide.

 

What if I need system access to a collection of child objects? Do I have to wrap them all in objects of a class defined without sharing, and provide accessor properties for each field I want to access?

 

I would have thought that I could access the fields of the sobject property freely since the containing class was defined without sharing, but my guess is that sobject classes are all defined with sharing.