If you want a tool that can understand cross object relationships, you are going to need a sophisticated approach indeed. It may be worth separating into the following tasks:
- Get the
referenceTo results for each field. Depending on how many times you are reusing this functionality in one context, it may be worth caching.
- Differentiate if you are at a root field or if you need traverse deeper into the map.
- Differentiate between standard and custom lookups and be able to convert the cross-object reference into the name of the field (e.g. Account.Name => AccountId).
If I had to do this all in one go it would look something like this before optimization:
static String getLookupName(String crossObjectReference)
// would need to think about this more if there are managed packages
return crossObjectReference.endsWith('__r') ?
crossObjectReference.replace('__r', '__c') :
crossObjectReference + 'Id';
public Parser(Schema.FieldSetMember member, Schema.SObjectType type)
this.path = member.getFieldPath().split('.');
this.type = type;
public Schema.DescribeFieldResult getDescribe()
// could possibly make this recursive
while (path.size > 1)
if (path.size() == 1) return;
String lookupName = getLookupName(path.remove(0));
Schema.DescribeFieldResult describe = describe(lookupName);
this.type = describe.getReferenceTo;
// this would get a lot more hairy if we want to deal with polymorphic lookups properly
Schema.DescribeFieldResult describe(String field)
Putting it all together
public static List<Schema.DescribeFieldResult> convertFields(List<Schema.FieldSetMember> members, Schema.SObjectType type)
List<Schema.DescribeFieldResult> describes = new List<Schema.DescribeFieldResult>();
for (Schema.FieldSetMember member : members)
describes.add(new Parser(member, type).getDescribe());