function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Vance Kessler 23Vance Kessler 23 

How to pull a Dependent Picklist Value Mapping in Apex

I was frustrated with the various answers I had found as to how to get a complete mapping of dependent picklist values, so I combined a few different posts into a solution that works, is efficient, and does not require a web service call. This only works for single level dependencies,

I created a class called Utilities that holds the method GetDependentOptions for getting dependent picklist values. There is also a method called GetPickListValues to retrieve values for a simple picklist. The method FirstControllingValueFor is used to do a reverse lookup given a child value to find the first controlling value that the child is valid for.

public class Utilities {
    public static List<String> GetPickListValues(String object_name, String field_name, String first_val) {
        SObjectType objectType = Schema.getGlobalDescribe().get(object_name);
        List<String> options = new List<String>(); //new list for holding all of the picklist options
        if (first_val != null) { //if there is a first value being provided
            options.add(first_val); //add the first option
        }
        List<String> classes = new List<String>();
        classes.add(object_name);
        List<Schema.DescribeSObjectResult> results = Schema.describeSObjects(classes);
        Schema.DescribeSObjectResult sobject_describe = results[0];
        Map<String, Schema.SObjectField> field_map = sobject_describe.fields.getMap(); //get a map of fields for the passed sobject
        if (null != field_map) {
            Schema.SObjectField fs = field_map.get(field_name);
            Schema.DescribeFieldResult dsr = fs.getDescribe();
            if (null != dsr) {
                List<Schema.PicklistEntry> pick_list_values = dsr.getPickListValues(); //grab the list of picklist values for the passed field on the sobject
                if (null != pick_list_values) {
                    for (Schema.PicklistEntry a : pick_list_values) { //for all values in the picklist list            
                        options.add(a.getValue());
                    }
                }
            }
        }
        return options; //return the List
    }
    
    private static Map<String, Integer> base64Vals = null;
    
    private static List<Integer> ConvertB64ToInts(string b64Str) {
        if (base64Vals == null) {
            base64Vals = new Map<String, Integer> {
                'A'=>00,'B'=>01,'C'=>02,'D'=>03,'E'=>04,'F'=>05,'G'=>06,'H'=>07,'I'=>08,'J'=>09,
                'K'=>10,'L'=>11,'M'=>12,'N'=>13,'O'=>14,'P'=>15,'Q'=>16,'R'=>17,'S'=>18,'T'=>19,
                'U'=>20,'V'=>21,'W'=>22,'X'=>23,'Y'=>24,'Z'=>25,'a'=>26,'b'=>27,'c'=>28,'d'=>29,
                'e'=>30,'f'=>31,'g'=>32,'h'=>33,'i'=>34,'j'=>35,'k'=>36,'l'=>37,'m'=>38,'n'=>39,
                'o'=>40,'p'=>41,'q'=>42,'r'=>43,'s'=>44,'t'=>45,'u'=>46,'v'=>47,'w'=>48,'x'=>49,
                'y'=>50,'z'=>51,'0'=>52,'1'=>53,'2'=>54,'3'=>55,'4'=>56,'5'=>57,'6'=>58,'7'=>59,
                '8'=>60,'9'=>61,'+'=>62,'/'=>63
            };
        }
        List<Integer> ints = new List<Integer>();
        for (Integer idx = 0; idx< b64Str.length(); ++idx) {
            String c = String.fromCharArray(new List<Integer> { b64Str.charAt(idx)});
            ints.add(base64Vals.get(c));
        }
        return ints;
    }

    private class TPicklistEntry{
        public string active {get;set;}
        public string defaultValue {get;set;}
        public string label {get;set;}
        public string value {get;set;}
        public string validFor {get;set;}
        public TPicklistEntry(){}
    }

    public static Map<String,List<String>> GetDependentOptions(String pObjName, String pControllingFieldName, String pDependentFieldName) {
        Map<String,List<String>> mapResults = new Map<String,List<String>>();

        //verify/get object schema
        Schema.SObjectType pType = Schema.getGlobalDescribe().get(pObjName);
        if ( pType == null ) return mapResults;
        Map<String, Schema.SObjectField> objFieldMap = pType.getDescribe().fields.getMap();

        //verify field names
        if (!objFieldMap.containsKey(pControllingFieldName) || !objFieldMap.containsKey(pDependentFieldName)) return mapResults;

        //get the control & dependent values
        List<Schema.PicklistEntry> ctrl_ple = objFieldMap.get(pControllingFieldName).getDescribe().getPicklistValues();
        List<Schema.PicklistEntry> dep_ple = objFieldMap.get(pDependentFieldName).getDescribe().getPicklistValues();

        //initialize results mapping
        for(Integer pControllingIndex=0; pControllingIndex < ctrl_ple.size(); pControllingIndex++) {
            mapResults.put( ctrl_ple[pControllingIndex].getLabel(), new List<String>());
        }

        //serialize dep entries
        List<TPicklistEntry> objDS_Entries = new List<TPicklistEntry>();
        objDS_Entries = (List<TPicklistEntry>)JSON.deserialize(JSON.serialize(dep_ple), List<TPicklistEntry>.class);

        for (TPicklistEntry objDepPLE : objDS_Entries){
            List<Integer> bitValues = ConvertB64ToInts(objDepPLE.validFor);

            Integer bitMask = 32; // Ignore highest 2 bits
            Integer intIndex = 0;
            Integer bitIdx = 0;
            for (Integer numBits = bitValues.size() * 6; numBits > 0; --numBits) {
                Integer bits = bitValues[intIndex];
                if ((bits & bitMask) == bitMask) {
                    mapResults.get( ctrl_ple[bitIdx].getLabel() ).add( objDepPLE.label );
                }
                bitMask = bitMask >>> 1;
                ++bitIdx;

                if (bitMask == 0) {
                    bitMask = 32;
                    intIndex = intIndex + 1;
                }
            }
        }
        return mapResults;
    }//GetDependentOptions
   
    public static String FirstControllingValueFor(String pObjName, String pControllingFieldName, String pDependentFieldName, String childValue) {
        Map<String,List<String>> mappedItems = GetDependentOptions(pObjName, pControllingFieldName, pDependentFieldName);
        for (String key : mappedItems.keySet()) {
            List<String> items = mappedItems.get(key);
            Set<String> itemSet = new Set<String>(items);
            if (itemSet.contains(childValue)) {
                return key;
            }
        }
        return null;
    }
}
Niket SFNiket SF
have you check this one ?

https://developer.salesforce.com/blogs/developer-relations/2008/12/using-the-metadata-api-to-retrieve-picklist-values.html

 
Vance Kessler 23Vance Kessler 23
I had seen code very similar to that link. The main purpose of the code I posted above was to pull dependent picklist values. The link above is only for pulling values from a single non-dependent picklist.

I only included GetPickListValues function to make the class a little more complete in respect to picklists.
Glyn Anderson (Slalom)Glyn Anderson (Slalom)
Vance, I recognize some of the code you combined from other posts (and there are many) on this problem.  I like what you've done with them.  It's two years later now, and I've come up with another version of the solution that uses only about 30 lines of Apex in a single method.  I've posted it in a blog post here: https://glyntalkssalesforce.blogspot.com/2018/08/dependent-picklist-values-in-apex.html, and I've included test code for 100% coverage.

I hope this can help you or others who might navigate to this forum question.