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;
...
...
}
}