[SalesForce] Is it still not possible to get the Related List Label of Lookup fields via APEX

We wrote a custom deduplication and merge tool allowing us to overcome the Salesforce limitation only to get the deduplication UI only for a few objects. Our tool needs to work on ANY SObject (custom + standard). Except for some Salesforce Bugs new in Winter '19, it just works fine most of the time.

We also handle the re-assignment of child-objects as part of the merge process.

Now we are showing the child relationships dynamically but use only the SObject Name (or Label to be more precisely). If there is only ONE child relationship of one SObject type, this might be sufficient, but on some custom Objects (e.g. elfBCProject__c) we have many lookups to Account and if we want to Dedupe-Merge two given Accounts now, we see many lines (in the screenshot it is Project and Order Form)

enter image description here

What we really would want to see instead is the Related List Label (including it's translated version done at translation workbench).

In the setup it is defined for ANY lookup or master-detail field:

enter image description here

But it looks like salesforce is not exposing this Related List Label. I found an 5 years old post here: Access the Related List Label for a Lookup relationship

And an idea here: https://success.salesforce.com/ideaView?id=08730000000JGzuAAG

This indicates, that it is likely still not possible to get the Related List Label via APEX. I just want to confirm here in this community, if we really still can't get that Label or if there might be a hack or a trick to get it now.

Best Answer

Oh, this is a nasty hack, but I'm using something similar right now to get listview info.

You can use the metadata api to get the field describes. There's a relationshipLabel value in the describe results. The problem, of course, is that the user needs API access to make this work at runtime...and that just isn't good.

/services/metadata/v43.0/components/objects/Account/fields/ownerid (Bad example since the OwnerId field doesn't have a label, but you get the picture.)

To get around the access issue, we're using a batch job (which runs as the system user) to grab all the describe info we need, and writing it to custom object records that we reference like a dictionary table in our code. Probably would have used Custom Settings if I had it to do over again, but for now, it works well-enough.

Like I said -- nasty, but problem solved.

UPDATE

Code sample, as requested ;)

public with sharing class ListViewMetadataRetriever extends ListviewMetadataBaseClass {
    /**
    * @description This method generates metadata for a specific listview
    * @param       listviewid - Id of ListView whose metadata is needed.
    * @return      ListViewMetaData - class containing info about the listview
    */
    public static ListViewDescribe getListViewDescribe(String sObjectName, String listviewid){

        String restAPIURL = getDescribePath(sObjectName, listviewId);
        System.debug(restAPIURL);

        HttpRequest httpRequest = getHttpRequest(restAPIURL);

        String response = '';
        ListViewDescribe descr;

        try {
            Http http = new Http();
            HttpResponse httpResponse = http.send(httpRequest);

            if (httpResponse.getStatusCode() == 200 ) {
                descr = (ListViewDescribe)JSON.deserialize(httpResponse.getBody(),ListViewDescribe.class) ;

            } else {
                throw new CalloutException( httpResponse.getBody() );

            }

        } catch(System.Exception e) {
            System.debug('ERROR: '+ e);
            throw e;
        }
        return descr;
    }

    private static HttpRequest getHttpRequest(String restApiUrl){
        HttpRequest httpRequest = new HttpRequest();
        httpRequest.setMethod('GET');
        httpRequest.setHeader('Authorization', 'OAuth ' + UserInfo.getSessionId());
        httpRequest.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionID());
        httpRequest.setEndpoint(restApiUrl);

        return httpRequest;
    }

    private static String getDescribePath(String sObjectName, String listviewId){
        String sfdcURL = URL.getSalesforceBaseUrl().toExternalForm(); 

        String pathStr = '';
        pathStr += sfdcUrl + '/services/data/v';
        pathStr += ListViewMetadataBaseClass.SFDC_API_VERSION + '.0';  //e.g. '44.0'
        pathStr += '/sobjects/' + sObjectName;
        pathStr += '/listviews/' + listviewId + '/describe';

        return pathStr;
    }

    private static String getInfoPath(String sObjectName){
        String sfdcURL = URL.getSalesforceBaseUrl().toExternalForm();

        String pathStr = '';
        pathStr += sfdcUrl + '/services/data/v';
        pathStr += ListViewMetadataBaseClass.SFDC_API_VERSION + '.0';  //e.g. '44.0'
        pathStr += '/sobjects/' + sObjectName;
        pathStr += '/listviews/';

        return pathStr;
    }

}

Base class:

public abstract class ListviewMetadataBaseClass {
    public static final String SFDC_API_VERSION = '42';
    ... 
    ... 
    public class ListViewDescribe{
        public list<Column> columns;
        public String query;
        ...
        ...
    }

}
Related Topic