Apex Language Features

#100 - sObject Type

Implement the method isTypeAccount(), which accepts a sObject as input and returns a true if type of input is Account object else it should return as false.
Given the following test code:

Account acc = new Account(name='Apple');
Boolean result = isTypeAccount(acc);

result should be equal to true

public Boolean isTypeAccount(sObject record) {
    if (record instanceof Account) {
        return true;
    }
    return false;
}
public Boolean isTypeAccount(sObject record)
{
    String sobjectType = record?.getSObjectType().getDescribe().getName();
    return (sobjectType == 'Account');
}

#93 - Convert 15-digit ID to 18-digit ID

Implement the method convert15to18DigitId(), which accepts a String of length 15 digit and returns a new String with 18 digit salesforce Id. If the input string length is not equal to 15 digits, then return -1.
Given the following test code:

String fifteenDigit = '0SO90000000PBDu';
String eighteenDigit = convert15to18DigitId(fifteenDigit);

eighteenDigit should be equal to ‘0SO90000000PBDuGAO’

Note:
Use case 1: You have exported a Salesforce report with Ids. These Ids are 15 characters. You want to ensure that these Ids are not altered by Excel, you need to manage them with 18 characters.
Use case 2: You need to compare Ids but your comparison mechanism is not case sensitive. You will have to extend them to 18 characters

public String convert15to18DigitId(String fifteenDigit)
{
    if (fifteenDigit?.length()==15) {
        return (Id)fifteenDigit;
    }
    return '-1';
}

#97 - Handle Exception

Implement the method divide which takes two integers a and b as input, divides a by b using the / operator, and returns the result. If any exception occurs, the method should return the exception message.
Given the following test code:

String result = divide(10,0);

result should be Divide by 0; Given the following test code:

String result = divide(100, 18);

result should be 5;. The result of integer division 100/19 is 5 with a remainder of 10.

public String divide(Integer a, Integer b){
    try {
        String result = String.valueOf(a/b);
        return result;
    }
    catch(Exception ex) {
        return ex.getMessage();
    }
}

#102 - Throw An Exception

Implement the method checkAccounts, which accepts a list of accounts as an input and returns a list of accounts. The method should behave as follows:

  • If all accounts in the list have BillingCity present, the method should return the original list.
  • If the passed list is null the method should throw the built-in IllegalArgumentException with message accounts should not be null
  • If any of the accounts in the list do not have a BillingCity present, the method should throw the custom AccountException exception. Do not create new exception class - use the AccountException class that has already been created for you.

Given the following test code:

List<Account> accounts = new List<Account>();
accounts.add(new Account(name ='Salesforce', BillingCity ='Boston'));
accounts.add(new Account(name ='Microsoft'));

The method callcheckAccounts(accounts); should fail, throwing an AccountException.

public List<Account> checkAccounts(List<Account> accounts)
{
    if (accounts == null) {
        throw new IllegalArgumentException('accounts should not be null');
    }
    for (Account a : accounts) {
        if (a.BillingCity == null) {
            throw new AccountException('Invalid BillingCity');
        }
    }
    return accounts;
}

//do not remove the following custom-defined exception
public class AccountException extends Exception {}

#94 - Safe Navigation Operator

Implement the method getAccountBillingCityWithSafeNavigation, which accepts a list of accounts as an input and returns the BillingCity in upper case of the first account in the list. Use the Safe Navigation (?.) to ensure null is returned in case the BillingCity is null.

Given the following test code:

List<Account> acts = new ListList<Account>();
acts.add(new Account(Name = 'Acme', BillingCity = 'Chicago'));
acts.add(new Account(Name = 'Dove', BillingCity = 'Boston'));
String result = getAccountBillingCityWithSafeNavigation(acts);

result should be ‘CHICAGO’

public String getAccountBillingCityWithSafeNavigation(List<Account> accounts){
   String billingCity = accounts[0].BillingCity?.toUpperCase();
   return billingCity;
}

#103 - Dynamic Field Values

Implement the method getFieldsValue, which accepts the following inputs:

  • An account acc
  • A list of strings fields, with each string in the list representing a valid field on the account object.
  • The method should return a list of values from the account record for fields listed in the list fields in the correct order.

Given the following test code:

Account acc = new Account(
    Name = 'Salesforce', 
    BillingCity = 'Boston', 
    AnnualRevenue=10000, Rating='Hot');
List fields = new List{'Industry','Name','Rating'};
List result = getFieldsValue(acc, fields);

result should be [null, 'Salesforce', 'Hot']

public List<String> getFieldsValue(Account acc, List<String> fields) {
    List<String> results = new List<String>();

    for (String field : fields) {
        String result = String.valueOf(acc.get(field));
        results.add(result);
    }

    return results;
}

#95 - Serialize sObjects

Implement the method getAccountsInJSONFormat(), a list of accounts and returns a list of accounts in string JSON format.

Given the following test code:

List<Account> accounts = new ListList<Account>();
accounts.add(new Account(Name = 'Acme', BillingCity = 'Chicago'));
accounts.add(new Account(Name = 'Dove', BillingCity = 'Boston'));
String result = getAccountsInJSONFormat(accounts);

result should be equals to

'[  {"attributes":
        {"type":"Account"},
        "Name":"Acme",
        "BillingCity":"Chicago"},
    {"attributes":
        {"type":"Account"},
        "Name":"Dove", 
        "BillingCity":"Boston"} ]';

Introducing JSON

public String getAccountsInJSONFormat(List<Account> accounts){
    String JSONString = JSON.serialize(accounts);

    return JSONString;
}

#101 - List of sObjects

Implement the method getListOfsObject(), which accepts two parameters, a list of accounts, and a list of contacts, as an input and returns a list of sObjects. If both lists are empty or null, return an empty list of sObject.

Given the following test code:

List<Account> accounts = new List<Account>();
accounts.add(new Account(name ='Salesforce'));
accounts.add(new Account(name ='Microsoft'));
List<Contact> contacts= new List<Contact>();
contacts.add(new Contact(lastName = 'Benioff'));
contacts.add(new Contact(lastName = 'Taylor'));
List result = getListOfsObject(accounts,contacts);

result should be (Account:{Name=Salesforce}, Account:{Name=Microsoft}, Contact:{LastName=Benioff}, Contact:{LastName=Taylor})

Note: Adding different types into a list of sObjects can be used to perform operations on multiple object types in a single DML operation.

public List<sObject> getListOfsObject(List<Account> accounts, List<Contact> contacts) {
    List<sObject> sobjects = new List<sObject>();
    
    if (accounts != null) {
        for (Account account : accounts) {
            sobjects.add(account);
        }
    }
    if (contacts != null) {
        for (Contact contact : contacts) {
            sobjects.add(contact);
        }
    }

    return sobjects;
}

#96 - Deserialize sObjects

Implement the method getAccountsFromJSONString, which takes a JSON string of a list of accounts as an input and returns a list of accounts. If the input string is empty or null, return null.

Given the following test code:

String inputJSON = '[
    {
        "attributes": {
            "type":"Account",
            "url":"/services/data/v55.0/sobjects/Account/00158000002zBhUAAU"
        },
        "Id" : "00158000002zBhUAAU",
        "Name":"Customer1"
    },
    {
        "attributes": {
            "type":"Account",
            "url":"/services/data/v55.0/sobjects/Account/00158000002zBhWAAU"
        },
        "Id":"00158000002zBhWAAU",
        "Name":"Customer2"
    }
]';
List<Account> result = getAccountsFromJSONString(inputJSON);
accounts.add(new Account(Name = 'Dove', BillingCity = 'Boston'));

result should be list of accounts (Account:{Id=00158000002zBhUAAU, Name=Customer1}, Account:{Id=00158000002zBhWAAU, Name=Customer2})

public List<Account> getAccountsFromJSONString(String inputJSON){
    if (String.isBlank(inputJSON)) {
        return null;
    } else {
        return (List<Account>) JSON.deserialize (inputJSON, List<Account>.class);
    }
}

#106 - Context User

Implement the method getContextUserInformation(), which returns a Map of the current logged in user’s (context user’s) UserName, ProfileId, EmailId, and Type as keys and their field values as corresponding values in the map.

Given the following sample code:

Map<String,String> userMap = getContextUserInformation();

The returned map should contain the following information:

Key Value
EmailId [email protected]
ProfileId 00e5g000021MG3eAAG
Type Standard
UserName [email protected]

Note: These values will be different for every user as they depend on the running user.

public Map<String,String> getContextUserInformation() {
   return new Map<String, String> {
       'EmailId' => UserInfo.getUserEmail(),
       'ProfileId'=> UserInfo.getProfileId(),
       'Type' => UserInfo.getUserType(),
       'UserName' => UserInfo.getUserName()
   };
}

#105 - Trigger Validation

Implement the method validateInsert, which accepts a newly inserted list of opportunities as an input and adds errors to the opportunity fields as follows: if the opportunity record’s StageName is Closed Won and the Description is null or empty, add an error on the Description field of that record with the error message set to Description should not be empty for Closed Won opportunity.

Please see the code snippet below for an example of how such a method can be used for custom validation in a before trigger:

Trigger OpportunityTrigger on Opportunity (before insert){ 
    if (Trigger.isBefore){ 
        OpportunityTriggerHandler handler = 
            new OpportunityTriggerHandler(); 
        List<Opportunity> opportunities = 
            handler.validateInsert(Trigger.new);
    }
}

Given the following test code:

List<Opportunity> oppList = new List<Opportunity>();
oppList.add(new Opportunity(
    StageName = 'Closed Lost', Description = 'Testing'));
oppList.add(new Opportunity(
    StageName = 'Closed Won'));
oppList.add(new Opportunity(
    StageName = 'Closed Won',Description ='Testing'));
oppList.add(new Opportunity(
    StageName = 'Qualification'));

validateInsert(oppList);

oppList should now contain 1 error message on 2nd record of the list with proper error message on the Description field.

public void validateInsert(List<Opportunity> opportunities){
    String msg = 'Description should not be empty for Closed Won opportunity.';

    for(Opportunity opp : opportunities) {
        if((opp.StageName == 'Closed Won') && 
            (opp.Description == '' || opp.Description == null)){
               opp.Description.addError(msg);
        }
    }
}

#98 - Sort List of sObjects

Implement the method getAccounts(), function, which accepts a list of accounts as input and returns a new list of accounts sorted in descending order based on the Annual Revenue field.

Given the following test code:

List<Account> accounts = new List<Account>();
accounts.add(new Account(Name='Accenture', AnnualRevenue = 30));
accounts.add(new Account(Name='TCS',AnnualRevenue = 10));
accounts.add( new Account( Name='Apple', AnnualRevenue = 100) );
List<Account> result = getAccounts(accounts);

result = (Account:{Name=Apple, AnnualRevenue=100}, Account:{Name=Accenture, AnnualRevenue=30}, Account:{Name=TCS, AnnualRevenue=10})

public List<Account> getAccounts(List<Account> accounts) {
    if(accounts == null) {
        return null;
    }

    List<AccountWrapper> accList = new List<AccountWrapper>();

    for(Account acc : accounts) {
        accList.add(new AccountWrapper(acc));
    }

    accList.sort();

    for(Integer i=0; i<accounts.size(); i++) {
        accounts[i] = accList[i].acc;
    }
    
    return accounts;
}

public class AccountWrapper implements Comparable {
    public Account acc; 

    public AccountWrapper(Account acc) {
        this.acc = acc;
    }

    public Integer compareTo(Object compareTo) {
        AccountWrapper aw = (AccountWrapper) compareTo;

        if (aw.acc.AnnualRevenue > this.acc.AnnualRevenue) {
            return 1;
        }

        return -1;
    }
}