[SalesForce] How to get the intersection of RecordType and Picklist values inside Apex

#Context#
This question has been asked before in the past and I've found several discussions of it here on StackExchange and elsewhere (links below to pages I've found in my research).

So far I'm not satisfied with any of the answers I've seen, and wanted to create this question just to poll the crowd one more time in case anything has changed in recent history that now makes this solvable.

#The Problem#
The basic challenge is easy to describe: You can use Schema Describe to obtain a list of picklist values for a given picklist field. That's not hard to do.

Where it gets tricky is if you have RecordType in the mix and the picklist is now being partially restricted based on the RecordType. If a field has say, 10 possible choices, but a RecordType restricts those choices down to 6, let's say, how do I know which six values are valid options for that field?

I want to obtain this information from inside an Apex class—this is the rub and what invalidates a lot of existing solutions to this problem.

#Possible Solutions#

  1. ###describeLayout()###
    Picklist value information seems to be readily available in the describeLayout() API call. Now if you've been around for a while you know people have gotten clever and learned to do a callout to the SF API from inside an Apex class but this feels too heavyweight for this purpose. Bringing in that API wrapper library and doing one of those self-calls just to know the right picklist values…there has to be a better way. (If you don't know what I'm talking about you can find it here: https://github.com/financialforcedev/apex-mdapi)
  2. ###<apex:inputField>###
    The inputField component is capable of all kinds of automagical stuff that isn't easily replicated, and this case is no exception. <apex:inputField> respects the RecordType and reduced set of values for the picklist field. Some folks have put together solutions that leverage this to reverse-engineer the list, in a way, by rendering inputField picklist selectors on a VisualForce page then pulling those values back off the HTML of the page. This is obviously a bit janky and requires the use of a VisualForce page.
  3. ###validFor?###
    I'm not even sure this is a possible approach, I'm fairly convinced it's a red herring at this point. A comment by the user Christophe Vidal on one of the questions in my research list below suggests that somehow validFor can be used to solve this problem. Some enterprising folks have figured out that even though validFor isn't documented as a property on PicklistEntry in Apex, you can extract it by serializing an instance to JSON and back. Then you have to chop it up using some bit manipulation to determine possible values. The purpose of "validFor" is to help people determine the connections between picklist values between controlling and dependent fields. I don't see how this can be extrapolated out to RecordTypes influencing picklists but if it's possible please do point me in the right direction.
  4. ###Hardcode it###
    Though I abhor this approach I feel it must be included to be fair and balanced. One strategy here that might work for your situation would be to just bake the subsets of values into your Apex. Or duplicate them somewhere like a CustomSetting and ask admins to maintain it alongside the RecordType restriction list.

#Conclusion#
I've been casting about for a few days now looking for a clean solution to this problem and really haven't found one. Since I actually have to solve this problem I will eventually be forced into one of the above options unless a more palatable one is presented by someone here (here's hoping!).

Since in my use case a VisualForce page is indeed involved I think I will likely go the "apex:inputField" route. Save me from that terrible fate, good StackExchangers!

#Related Links and Discussions#

  1. https://stackoverflow.com/questions/7810801/how-to-describe-enumerate-picklist-enties-valid-for-a-specific-record-type-in
  2. https://developer.salesforce.com/forums?id=906F00000008z44IAA
  3. http://titancronus.com/blog/2014/07/03/acquiring-dependent-picklists-in-apex-contd/
  4. https://success.salesforce.com/ideaView?id=08730000000bhbwAAA
  5. https://developer.salesforce.com/forums/?id=906F00000008nNrIAI
  6. https://stackoverflow.com/questions/8560522/salesforce-record-type-and-opportunity-stage-relationship-database-location
  7. https://success.salesforce.com/ideaView?id=08730000000l6O5AAI
  8. https://github.com/financialforcedev/apex-mdapi/issues/4

Best Answer

You can make use the User Interface API to get picklist values based on record type, https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_resources_picklist_values.htm

However, you need to make a REST API call and set Remote Site Settings. Here is the sample code for that,

Http http = new Http();
HttpRequest request = new HttpRequest();
String shost = System.Url.getSalesforceBaseURL().toExternalForm();
String url = shost + '/ui-api/object-info/{objectApiName}/picklist-values/{recordTypeId}/{fieldApiName}';
request.setEndpoint(url);
request.setMethod('GET');

// set Authorization 
request.setHeader('Authorization', 'OAuth '+UserInfo.getSessionId());
HttpResponse response = http.send(request);

You need to replace {objectApiName}, {recordTypeId} and {fieldApiName} with appropriate values. If anyone found a better solution not mentioned in the lists, please update.

Related Topic