Yes, by using JSON serialization or by referencing an undocumented property compoundFieldName
on Schema.DescribeFieldResult
.
The API version of a field describe result includes this key. If non-null, the present field is a component of a compound field, whose API name is populated in that key.
This field is not (documented to be) available on Schema.DescribeFieldResult
, but if you serialize the object, the data is present. Additionally, it can be referenced in Apex, even through it's undocumented:
Contact.OtherStreet.getDescribe().compoundFieldName
or
Contact.OtherStreet.getDescribe().getCompoundFieldName()
Hence, an approach like this is possible:
public class CompoundFieldUtil {
public static List<SObjectField> getEntityParticles(SObjectType objectType, SObjectField field) {
Map<String, SObjectField> fieldMap = objectType.getDescribe().fields.getMap();
List<SObjectField> components = new List<SObjectField>();
String thisFieldName = field.getDescribe().getName();
for (String s : fieldMap.keySet()) {
if (fieldMap.get(s).getDescribe().compoundFieldName == thisFieldName) {
components.add(fieldMap.get(s));
}
}
return components;
}
}
Then,
System.debug(CompoundFieldUtil.getEntityParticles(Contact.sObjectType, Contact.OtherAddress));
yields
14:15:14:523 USER_DEBUG [1]|DEBUG|(OtherStreet, OtherCity, OtherState, OtherPostalCode, OtherCountry, OtherStateCode, OtherCountryCode, OtherLatitude, OtherLongitude, OtherGeocodeAccuracy)
The JSON serialization form also works, but is approximately five times slower:
public class CompoundFieldUtil {
public static List<SObjectField> getEntityParticles(SObjectType objectType, SObjectField field) {
Map<String, SObjectField> fieldMap = objectType.getDescribe().fields.getMap();
List<SObjectField> components = new List<SObjectField>();
String thisFieldName = field.getDescribe().getName();
for (String s : fieldMap.keySet()) {
Map<String, Object> describeData = (Map<String, Object>)JSON.deserializeUntyped(
JSON.serialize(fieldMap.get(s).getDescribe())
);
if (describeData.containsKey('compoundFieldName')
&& (String)describeData.get('compoundFieldName') == thisFieldName) {
components.add(fieldMap.get(s));
}
}
return components;
}
}