a guy i kno
a guy i kno

Reputation: 13

Is there a good way in Salesforce to use an Apex class to split a full name string into first name, middle name(s), and last name?

I'm trying to make some of the automation at my org more accurate, creating Contact records when a custom Full Name field on an Opportunity record is added for the first time, but I'm having difficulty implementing it. In the interest of making it more modular and implementing it on multiple objects, I'm trying to use an InvocableMethod embedded in an existing Flow, and all it needs is a string input to return a first name, a last name, and a middle name using the String.split() method, with the caveat that if there is more than one name between the first and last, assuming that all of them are a part of the middle name (i.e. if the full name is "Kiefer William Frederick Dempsey George Rufus Sutherland," it would return "Kiefer" as the first name, "Sutherland" as the last name, and "William Frederick Dempsey George Rufus" as the middle name).

This is my first attempt at implementing an InvocableMethod and my first time adding Apex to a Flow, and I'm trying to combine several solutions I found online at the same time, so I'm hoping someone can point out any flaws in my approach or misunderstandings I may have.

I followed a basic template I found here that helped me get the structure of the Apex class down, and then a response to an article on a Java forum here as a guideline to help me with how to actually split the name since I haven't used Apex or Java very much to date. The result is as follows:

public class getFirstMiddleLastNames {
    
    @InvocableMethod
    public static List<ReturnVariables> getFirstMiddleLastNames(List<InputVariables> inputVariables) {
        
        // Get the inputs
        String name = inputVariables.get(0).name;
        
        // Define output variables
        String newFirstName;
        String newMiddleNames;
        String newLastName;
        
        // Perform logic
        List<String> result = name.split(' ');
        newFirstName = result.get(0);
        newLastName = result.get(result.size()-1);
        if (result.size() >= 3){
            for (Integer i = 1; i < result.size()-1; i++){
                newMiddleNames = newMiddleNames + result.get(i) + ' ';
            }
        }
        
        // Get the output values
        List<ReturnVariables> returnVarsList = new List<ReturnVariables>();
        ReturnVariables returnVars = new ReturnVariables();
        returnVars.firstName = newFirstName;
        returnVars.middleNames = newMiddleNames;
        returnVars.lastName = newLastName;
        
        return returnVarsList;
    }
    
    public class InputVariables{
        // Used a list in case I need to add more inputs down the line
        @InvocableVariable
        public String name;
    }
    
    public class ReturnVariables{
        @InvocableVariable
        public String firstName;
        
        @InvocableVariable
        public String middleNames;
        
        @InvocableVariable
        public String lastName;
    }
}

When I added this to my Flow and tried triggering it, I got errors stating that it failed essentially due to a null value in Contact.LastName. Testing it in Debug mode in the Flow, it gave me the below text during the Apex step, and then failed one step later when it tried to create a Contact where the Contact.LastName field is a null value:

Inputs

name = {!$Record.primary_contact__c} (Kiefer William Frederick Dempsey George Rufus Sutherland)
Outputs

{!newPrimaryContactLastName} = lastName (null)
{!newPrimaryContactFirstName} = firstName (null)
{!newPrimaryContactMiddleNames} = middleNames (null)

I've seen some people swap in name.split('\s') where I used name.split(' ') as a way to split on all whitespace values, but that had the same result. I started out using = result[0] and = result[result.size()-1] with no change in results, and I've also tried changing newFirstName = result.get(0); to newFirstName = 'Steve'; to see if it would result in a first name actually being found by the code, but it still resulted in a null value.

Is there something I'm missing?

Upvotes: 0

Views: 1015

Answers (1)

eyescream
eyescream

Reputation: 19612

You create your return array and you build the complex object that will be the first (and only) element returned - but you don't actually add it to the array.

List<ReturnVariables> returnVarsList = new List<ReturnVariables>();
ReturnVariables returnVars = new ReturnVariables();
returnVars.firstName = newFirstName;
returnVars.middleNames = newMiddleNames;
returnVars.lastName = newLastName;
        
returnVarsList.add(returnVars); // this was missing
        
return returnVarsList;

Should work better but you may find an extra "null" in the result you didn't expect. I'm not saying this is 100% fool-proof but may be bit simpler and better handling bulk situations when multiple opportunities enter this Flow:

@InvocableMethod
    public static List<ReturnVariables> getFirstMiddleLastNames(List<InputVariables> inputVariables) {
        
        List<ReturnVariables> returnVarsList = new List<ReturnVariables>();
        for(InputVariables i : inputVariables){
            ReturnVariables ret = new ReturnVariables();
            List<String> tokens = i.name.split(' ');
            ret.firstName = tokens.remove(0);
            ret.lastName = tokens.remove(tokens.size() - 1);
            ret.middleNames = String.join(tokens, ' ');
            returnVarsList.add(ret);
        }
        return returnVarsList;
    }

If you call it with this test case (you could use it as base for unit test):

List<getFirstMiddleLastNames.InputVariables> inputs = new List<getFirstMiddleLastNames.InputVariables>{
    new getFirstMiddleLastNames.InputVariables(),
    new getFirstMiddleLastNames.InputVariables()
};
inputs[0].name = 'Kiefer William Frederick Dempsey George Rufus Sutherland';
inputs[1].name = 'Charles Philip Arthur George Windsor';

System.debug(getFirstMiddleLastNames.getFirstMiddleLastNames(inputs));

You'll get

ReturnVariables:[firstName=Kiefer, lastName=Sutherland, middleNames=William Frederick Dempsey George Rufus], ReturnVariables:[firstName=Charles, lastName=Windsor, middleNames=Philip Arthur George]

Upvotes: 0

Related Questions