ApexDoc Examples

See practical examples of ApexDoc comments applied to various Apex constructs.

Class Example

/**
 * Manages customer account information and related operations.
 * This class bypasses user record access via 'without sharing' so that it 
 * can be used in a batch classes.
 * @author John Developer
 * @since 0.1.0
 * @version 0.3.1
 * @see AccountProcessingBatch
 * @group Account
 * @example
 * {@code
 * Account a;
 * try {
 *  a = new AccountManager().createAccount('Acme', 'Agriculture');
 * } catch (AccountManager.AccountException caught) {
 *   LOGGER.log(caught);
 *   // further exception handling
 * }
 * }
 */
public without sharing class AccountManager {

    /**
     * The default region for new accounts if not specified.
     */
    public static final String DEFAULT_REGION = 'North America';

    /**
     * Stores the count of active accounts managed by this instance.
     * Populated after using the {@link AccountService}.
     */
    @TestVisible
    private Integer activeAccountCount;

    /**
     * Creates a new Account sObject with the given name and industry.
     * @param accountName The desired name for the new account. Cannot be null or empty.
     * @param industry The industry classification for the new account.
     * @return The newly created Account sObject with its ID populated.
     * @throws AccountManager.AccountException if accountName is invalid
     * or if DML operation fails.
     */
    public Account createAccount(String accountName, String industry) {
        if (String.isBlank(accountName)) {
            throw new AccountManager.AccountException('Account name cannot be blank.');
        }
        Account acc = new Account(Name = accountName, Industry = industry);
        // Potentially more logic here
        try {
            insert as user acc;
        } catch (DmlException e) {
            throw new AccountManager.AccountException(
                'Failed to create account: ' + e.getMessage()
            );
        }
        return acc;
    }

    // more methods...

    /**
     * Represents an exception specific to AccountManager operations.
     * @example
     * {@code
     * throw new AccountManager.AccountException('Account not found with provided Id.');
     * }
     */
    public with sharing class AccountException extends Exception {}
}

Packaged Class Example

/**
 * Provides services for geolocation and address conversion.
 * @author Dennis Smith
 * @version 0.3.0
 * @since 0.1.0
 */
global with sharing class GeolocationService {
  /**
   * Represents geographic coordinates (latitude and longitude).
   */
  global with sharing class Coordinates {
    @AuraEnabled
    public Decimal latitude;
    @AuraEnabled
    public Decimal longitude;

    global Coordinates(Decimal lat, Decimal lon) {
      this.latitude = lat;
      this.longitude = lon;
    }
  }

  /**
   * Converts a full address string to approximate latitude
   * and longitude coordinates. This method is deprecated and should no
   * longer be used due to its reliance on an older, less accurate geocoding 
   * service and simpler parsing logic. It may not handle all address formats
   * correctly and has a lower success rate.
   * @param fullAddress The complete address string
   * (e.g., "123 Main St, Anytown, CA 90210, USA").
   * @return A `Coordinates` object representing the approximate latitude and longitude.
   * @throws DeprecatedMethodCalledException If this method is invoked,
   * informing the user to migrate to the newer, more robust `geocodeAddress` method.
   * @deprecated in 0.2.0. Use {@link #geocodeAddress(
   * String street,
   * String city,
   * String state,
   * String postalCode,
   * String country)} instead.
   * @since 0.1.0
   */
  @Deprecated
  global static Coordinates convertAddressToCoordinates(String fullAddress) {
    throw new DeprecatedMethodCalledException(
      'The method `GeolocationService.convertAddressToCoordinates(String fullAddress)` is deprecated. ' +
        'Please use `GeolocationService.geocodeAddress(String street, String city, String state, String postalCode, String country)` ' +
        'for all new and existing address-to-coordinate conversions to ensure better accuracy and reliability.'
    );
  }

  /**
   * Geocodes a structured address into precise latitude and longitude coordinates
   * using a robust external geocoding service.
   * This method provides higher accuracy and better handling of diverse address formats.
   * @param street The street address (e.g., "123 Main St").
   * @param city The city (e.g., "Anytown").
   * @param state The state or province abbreviation (e.g., "CA").
   * @param postalCode The postal or ZIP code (e.g., "90210").
   * @param country The country name or code (e.g., "USA").
   * @return A Coordinates object containing the latitude and longitude.
   * @throws GeocodingException If the address cannot be geocoded, 
   * if the external service is unavailable, or if required address
   * components are missing.
   * @example
   * {@code
   * try {
   *   GeolocationService.Coordinates coords = GeolocationService.geocodeAddress(
   *     '415 Mission St',
   *     'San Francisco',
   *     'CA',
   *     '94105',
   *     'USA'
   *   );
   * } catch (GeolocationService.GeocodingException e) {
   *   // handle failure
   * }
   * }
   * @since 0.2.0
   */
  global static Coordinates geocodeAddress(
    String street,
    String city,
    String state,
    String postalCode,
    String country
  ) {
    // Implement actual geocoding logic
    return new Coordinates(0, 0);
  }

  /**
   * Exception thrown when a deprecated method is called.
   * This indicates that the caller should migrate to the recommended alternative.
   */
  global with sharing class DeprecatedMethodCalledException extends Exception {
  }

  /**
   * Exception thrown when a geocoding operation fails.
   * This provides specific context for issues during address-to-coordinate conversion.
   */
  global with sharing class GeocodingException extends Exception {
  }
}

Test Class Example

/**
 * Specifications for the GeolocationService
 * @author Jane Devington
 * @version 0.2.0
 * @see GeolocationService
 * @since 0.1.0
 */
@IsTest
private with sharing class GeolocationServiceTest {
  /**
   * Verifies that known addresses are correctly geocoded to their expected coordinates.
   * @see GeolocationService#geocodeAddress(
   * String street,
   * String city,
   * String state,
   * String postalCode,
   * String country)
   */
  @IsTest
  private static void validAddressShouldReturnCorrectCoordinates() {
    String street = '415 Mission Street';
    String city = 'San Francisco';
    String state = 'CA';
    String postalCode = '94105';
    String country = 'USA';

    GeolocationService.Coordinates coords;
    Test.startTest();
    coords = GeolocationService.geocodeAddress(
      street,
      city,
      state,
      postalCode,
      country
    );
    Test.stopTest();

    Assert.isNotNull(
      coords,
      'Coordinates should not be null for a valid address.'
    );
    Assert.areEqual(
      37.785834,
      coords.latitude,
      'Latitude should match for Salesforce tower.'
    );
    Assert.areEqual(
      -122.406417,
      coords.longitude,
      'Longitude should match for Salesforce tower.'
    );
  }

  /**
   * Verifies that calling the geocodeAddress with missing required parameters
   * throws a GeocodingException.
   * @see GeolocationService#geocodeAddress(
   * String street,
   * String city,
   * String state,
   * String postalCode,
   * String country)
   * @see GeolocationService#GeocodingException
   */
  @IsTest
  private static void missingRequiredParametersShouldThrowGeocodingException() {
    String street = ''; // Missing
    String city = 'San Francisco';
    String state = 'CA';
    String postalCode = 94105;
    String country = 'USA';

    Test.startTest();
    Boolean caughtException = false;
    try {
      GeolocationService.geocodeAddress(
        street,
        city,
        state,
        postalCode,
        country
      );
    } catch (GeolocationService.GeocodingException e) {
      caughtException = true;
      Assert.areEqual(
        'Street, City, and Postal Code are required for geocoding.',
        e.getMessage(),
        'Exception message should indicate missing required fields.'
      );
    }
    Test.stopTest();

    Assert.isTrue(
      caughtException,
      'GeocodingException should have been thrown for missing street.'
    );
  }

  /**
   * Verifies that calling the deprecated method throws a
   * DeprecatedMethodCalledException.
   * @see GeolocationService#convertAddressToCoordinates(String address)
   * @see GeolocationService#DeprecatedMethodCalledException
   */
  @IsTest
  private static void deprecatedMethodCallShouldThrowDeprecatedMethodCalledException() {
    String oldAddress = '123 Deprecated Lane';

    Test.startTest();
    Boolean caughtException = false;
    try {
      GeolocationService.convertAddressToCoordinates(
        oldAddress
      );
    } catch (GeolocationService.DeprecatedMethodCalledException e) {
      caughtException = true;
      Assert.isTrue(
        e.getMessage().contains('is deprecated'),
        'Exception message should indicate deprecation.'
      );
      Assert.isTrue(
        e.getMessage().contains('Please use'),
        'Exception message should suggest new method.'
      );
    }
    Test.stopTest();

    Assert.isTrue(
      caughtException,
      'DeprecatedMethodCalledException should have been thrown.'
    );
  }
}

Interface Example

/**
 * Defines a contract for objects that can be serialized to a 
 * specific format. Implementations must provide logic for converting
 * their state into a string representation.
 * @author Jane Coder
 * @since 0.2.0
 */
public interface ISerializable {
    /**
     * Serializes the object's current state into a String.
     * @return A String representation of the object.
     * @throws SerializationException if the object cannot be serialized.
     */
    String serialize();

    /**
     * Gets the format name this serializer supports (e.g., "JSON", "XML").
     * @return The name of the serialization format.
     */
    String getFormatName();
}

Enum Example

/**
 * Represents the possible status levels for a support case.
 * Defines standard values for case progression in the customer portal. 
 * @author John Developer
 * @since 0.1.5
 */
public enum CaseStatus {
  /* A newly opened case, not yet assigned. */
  BRAND_NEW,
  /* Case is actively being worked on. */
  WORKING,
  /* Case has been escalated to a higher tier. */
  ESCALATED,
  /* Case has been resolved and closed. */
  CLOSED
}

Method Example (with params, return, throws)

/**
 * Calculates the total price for a list of products, applying a discount.
 * @param productCodes A List of unique product codes to calculate the price for.
 * Each code must correspond to an existing Product2 record.
 * @param discountPercentage The discount percentage to apply (e.g., 10.5 for 10.5%).
 * Must be between 0.0 and 100.0.
 * @return The calculated total price as a Decimal after applying the discount.
 * Returns 0.0 if productCodes is null or empty.
 * @throws InvalidArgumentException if discountPercentage is out of range.
 * @throws ProductNotFoundException if any productCode does not match an
 * existing product.
 */
public Decimal calculateTotalPrice(
  List<String> productCodes,
  Decimal discountPercentage
) {
    if (discountPercentage < 0.0 || discountPercentage > 100.0) {
        throw new IllegalArgumentException(
          'Discount percentage must be between 0.0 and 100.0.'
        );
    }
    if (productCodes == null || productCodes.isEmpty()) {
        return 0.0;
    }
    //... implementation logic to fetch prices and calculate total...
    return 100.0;
}

/**
 * Represents an exception thrown when a requested product cannot be found.
 * This custom exception provides a clear indication that a product lookup failed,
 * allowing calling code to handle the 'not found' scenario specifically.
 * It is typically thrown by methods attempting to retrieve Product2 records.
 * @example
 * {@code
 * List<Product2> products = [
 *   SELECT Id
 *   FROM Product2
 *   WHERE ProductCode = :productCode
 *   LIMIT 1
 * ];
 * if (products.isEmpty()) {
 *   throw new ProductNotFoundException(
 *    'Product with code ' + productCode + ' not found.'
 *  );
 * }
 * }
 */
public with sharing class ProductNotFoundException extends Exception {} 

Annotated Method (@AuraEnabled) Example

public with sharing class OpportunityService {
    /**
     * Retrieves a list of open opportunities for a given account,
     * accessible from Lightning Web Components. If the set of open opportunities
     * can change during interaction with the component, the author will 
     * need to use {@code refreshApex()}. 
     * @param accountId The ID of the Account to retrieve opportunities for.
     * @return A List of open Opportunity records. Returns an empty list if no
     * open opportunities are found or if accountId is invalid.
     * @see OpportunitySelector
     */
    @AuraEnabled(cacheable=true)
    public static List<Opportunity> getOpenOpportunities(Id accountId) {
        List<Opportunity> result = new List<Opportunity>();
        //... implementation details...
        return result;
    }
}

External Reference Example

/**
 * Provides a service to retrieve current weather conditions from an external API.
 * It utilizes Salesforce Named Credentials for secure endpoint and
 * authentication management.
 * @author John Doe
 * @since 1.0.3
 */
public with sharing class WeatherService {
  /**
   * Retrieves the current weather conditions for a specified city and country.
   * This method makes an HTTP GET callout to an external weather API using a
   * Named Credential.
   * @param city The name of the city (e.g., "London").
   * @param country The name or code of the country (e.g., "UK" or "United Kingdom").
   * @return A JSON string representing the current weather conditions.
   * @throws WeatherServiceException If the HTTP callout fails, returns a non-200 status,
   * or if there's an issue parsing the response.
   * @see <a href="https://example.com/weather-api-docs/current-conditions.html">External 
   * Weather API</a>
   */
  public static String getCurrentWeather(
    String city,
    String country
  ) {
    if (String.isBlank(city) || String.isBlank(country)) {
      throw new WeatherServiceException(
        'City and country cannot be blank for weather lookup.'
      );
    }

    String namedCredentialUrl = 'callout:WeatherAPI/current'; 
    String requestParams =
      '?city=' +
      EncodingUtil.urlEncode(city, 'UTF-8') +
      '&country=' +
      EncodingUtil.urlEncode(country, 'UTF-8');

    HttpRequest req = new HttpRequest();
    req.setEndpoint(namedCredentialUrl + requestParams);
    req.setMethod('GET');
    req.setTimeout(60000);

    Http http = new Http();
    HttpResponse res;

    try {
      res = http.send(req);
    } catch (System.CalloutException e) {
      throw new WeatherServiceException(
        'HTTP Callout Failed: ' + e.getMessage()
      );
    }

    if (res.getStatusCode() == 200) {
      return res.getBody();
    } else {
      throw new WeatherServiceException(
        'Failed to retrieve weather data. Status: ' +
          res.getStatusCode() +
          '. Details: ' +
          res.getBody()
      );
    }
  }

  /**
   * Custom exception for errors during weather data retrieval.
   */
  public with sharing class WeatherServiceException extends Exception {
  }
}

Inline Tags Example

/**
 * Sanitizes a given input string by removing or replacing certain
 * characters such as {@code <script>}
 * @param inputString The raw string provided by a user or external source. 
 * This string might contain malicious or unexpected characters,
 * like a {@literal <script>} tag or a backslash {@literal \}.
 * @return The sanitized string after processing.
 * @example
 * {@code
 * String badInput = 'Hello, <script>alert(\'xss\')</script> World!';
 * String safeOutput = SecurityUtils.sanitizeInput(badInput);
 * System.debug('Sanitized Output: ' + safeOutput);
 * } * @see {@link String#escapeHtml4} for a similar built-in method.
 * {@hidden NOTE TO MAINTAINERS: This method should be updated if
 * new security threats are identified. The current regex
 * is designed to handle common XSS patterns but may not
 * be exhaustive. The last major update was in v2.1.}
 * @since 2.0
 */
global static String sanitizeInput(String inputString) {
  // simple example for demonstration purposes
  String sanitized = inputString;
  sanitized = sanitized.replace('<script>', '').replace('</script>', '');
  sanitized = sanitized.replace('&#40;','(').replace('&#41;',')');
  return sanitized;
}