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
3 Creeks3 Creeks 

Getting object names to use for Metadata.Operations.retrieve

Working with the Metadata Class introduced with ver 40, is there a way to dynamically build a list of Object names to be used in Metadata.Operations.retrieve?  The full names formatted in the way that Metadata.Operations.retrieve wants them are not found in the results of a Schema.getGlobalDescribe() so I am wondering if there is some where else to get this.

A use case would be displaying a list object names to the user of the objects that a custom button can be added to.

Thanks
Alain CabonAlain Cabon
Hi,

Could you try the code below as an anonymous code first?

https://help.salesforce.com/articleView?id=code_dev_console_execute_anonymous.htm&type=0
        String svcURL = '/services/data/v40.0/sobjects/';
        HttpRequest req = new HttpRequest();    
        req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionID());
        req.setHeader('Content-Type', 'application/json');        
        String domainUrl = URL.getSalesforceBaseUrl().toExternalForm();        
        req.setEndpoint(domainUrl + svcURL);
        req.setMethod('GET');                 
        Http h = new Http();
        HttpResponse res = h.send(req);
        system.debug(res);
        String resp = res.getBody();
        system.debug(resp);
        Pattern MyPattern = Pattern.compile('(?m)"name":"(.+?)"');
        Matcher MyMatcher = MyPattern.matcher(resp);
        while (MyMatcher.find()) {
           if (MyMatcher.group(1).endsWith('__mdt')) {
              system.debug('mdt: ' + MyMatcher.group(1));
           }  
        }

I think it is the shorter solution that could work for your problem.

Pattern MyPattern = Pattern.compile('(?m)"name":"(.+?)"');
Pattern MyPattern = Pattern.compile('(?m)"label":"(.+?)"');  // for the labels

I don't parse the JSON response because I got an error during this parsing that you could also have.
        Map<String, Object> resultMap = (Map<String, Object>) JSON.deserializeUntyped(resp);
        List<Object> records = (List<Object>) resultMap.get('sobjects');     
        for (Integer i = 0; i < records.size(); i++) {
            Map<String, Object> row = (Map<String, Object>) records[i];        
            string name = (string) row.get('name');
            string label= (string) row.get('label');
            system.debug(name + '=' + label);
        }

You could get an error during the first launch of the code because a Remote Site is missing. The error message is clear and gives the "how to" for solving the problem (menu and end point).

Regards
3 Creeks3 Creeks
Thanks for the response Alain.  Your code may get me close, but my hope was to not have to do a call out and to get a list that has the definitive names of the Objects in the way that the Metadata.Operations.retrieve() method expects them.  For instance, to get a layout for Contact you send it 'Contact-Contact Layout'.  I can build that string easy enough for standard objects but it can get more complex for custom objects in a managed package.  It would also be very nice that, if I can get that list, to tie the objects back to the object attributes given by Schema.getGlobalDescribe() so I can filter based on more of the object attributes then the call out you suggested returns.  

Since the Metadata class was just introduced in Summer 2017, perhaps there is no way to get this info real clean and it is going to take something similar to what you suggest.
 
Alain CabonAlain Cabon
The system.debug(resp);  above is display below for a metadata type object.

There is a misunderstanding because you want the layout names and not the metadata types names (__mdt)  

You never wrote that your problem was the layout names for the Schema.getGlobalDescribe().

You can parse the JSON or get all these informations:

{"activateable":false,"createable":false,"custom":true,"customSetting":false,
"deletable":false,"deprecatedAndHidden":false,"feedEnabled":false,"hasSubtypes":false,
"isSubtype":false,"keyPrefix":"m00",
"label":"MyMetadataTest",
"labelPlural":"MyMetadataTests",
"layoutable":true,"mergeable":false,
"mruEnabled":true,
"name":"MyMetadataTest__mdt",
"queryable":true,"replicateable":false,
"retrieveable":true,"searchable":false,"triggerable":false,"undeletable":false,"updateable":false,
"urls":{"rowTemplate":"/services/data/v40.0/sobjects/MyMetadataTest__mdt/{ID}",
"defaultValues":"/services/data/v40.0/sobjects/MyMetadataTest__mdt/defaultValues?recordTypeId&fields",
"describe":"/services/data/v40.0/sobjects/MyMetadataTest__mdt/describe",
"layouts":"/services/data/v40.0/sobjects/MyMetadataTest__mdt/describe/layouts",
"sobject":"/services/data/v40.0/sobjects/MyMetadataTest__mdt"}},

You want to get the layouts so you need to a second call with  /services/data/v40.0/sobjects/MyMetadataTest__mdt/describe/layouts 
and then you have to parse the result (JSON / regular expression ).

Pattern MyPatternLayouts = Pattern.compile('(?m)"layouts":"(.+?)"');

I spent a lot of time for solving this problem of layout names for the Schema.getGlobalDescribe() in another way (but quite similar for the principle).

User-added image

It is tricky but I solved also this complicated problem for my own tool I will publish soon based on the Metadata Class introduced with ver 40.
I spent a lot of time for getting a maximum of informations from this new Metadata Class.

Regards