ApexDoc:文档化你的 Apex 代码

ApexDoc文档化指南:涵盖基本注释格式(/** */与普通注释区分/紧接被描述元素/跨行星号语法/主描述的一句话摘要规则)、完整块标签参考(@author/@deprecated/@param/@return/@throws/@see/@since/@example/@version/@group)和内联标签({@code}/{@link}/{@literal}/{@hidden})、各类Apex构造的文档化指南(类/接口/枚举/方法/构造函数/属性/触发器)、关键注解文档化要点(@AuraEnabled/@InvocableMethod/@Future/@Deprecated/@IsTest/@TestVisible/@RestResource)以及完整的实践代码示例(AccountManager类/GeolocationService地理编码服务/@AuraEnabled方法)。...

📅 2026/7/16 ✍️ ponybai 🏷️ apex, salesforce

文档化你的 Apex 代码

ApexDoc

ApexDoc 是一种标准化的注释格式,使人类、文档生成器和 AI Agent 更容易理解你的代码库。我们强烈推荐使用 ApexDoc 注释来促进代码协作并提高长期代码可维护性。基于 JavaDoc 标准,ApexDoc 提供了专为 Apex 和 Salesforce 生态系统定制的语法规范、专用标签和指南。注意:虽然 Apex 编译器强制执行现有注释语法,但不强制 ApexDoc 语法或检查注释准确性。

ApexDoc 基本注释格式

基本格式

ApexDoc 注释通过起始分隔符与普通 Apex 注释区分:普通多行注释使用 /* */ApexDoc 注释以 /** 开头,以 */ 结尾。ApexDoc 注释紧接在它文档化的类、接口、枚举、方法、构造函数或属性声明之前——注释块和被描述元素之间不能有其他代码或注释。

如果 ApexDoc 跨越多行,每个后续行以星号(*)开头。文档解析器忽略前导星号及其之前的空白:

/**
 * 这是一个简单的 ApexDoc 注释。
 */
public with sharing class MyClass {
    //...
}

主描述:ApexDoc 注释中的第一个文本块——没有显式标签。首先包含一个一句话摘要(用句号结尾——文档生成工具通常提取此句用于摘要表或索引),然后提供关于该元素的任何额外上下文(如前置/后置条件、链接到相关文档或描述变量约束)。

ApexDoc 块标签与内联标签

标签

块标签用于 ApexDoc 注释的主描述之后。以 @ 符号开头后跟标签名。每个块标签出现在新行上,相关信息在标签名之后。关键块标签包括:

标签适用元素说明
@author valueClass/Interface/Enum作者,允许多个 @author
@deprecated description所有标记弃用,提供原因和替代方案
@param paramName descriptionMethod/Constructor参数说明——必须匹配参数顺序和名称
@return descriptionMethod返回值说明——void 方法和构造函数不使用
@throws exceptionType descMethod/Constructor文档化可能抛出的异常
@see reference所有添加"参见"引用——支持 @see class#member、@see "文本"、@see [label](URL)
@since value所有版本或日期——对包作者特别有用
@example example所有使用示例(配合 {@code} 格式化为代码)
@version valueClass/Interface/Enum元素版本

内联标签用于主描述或块标签描述中。以 @ 开头但用花括号包围({@...}):

  • {@code text} —— 将文本格式化为内联代码
  • {@link reference} —— 创建到另一个元素的内联链接(语法同 @see)
  • {@literal text} —— 不解释 HTML 标签,直接显示字面文本
  • {@hidden text} —— 阻止元素出现在生成的文档中

文档化类与接口

类与接口

类文档化:在摘要句中描述类的总体目的。解释共享模型选择的原因(如为什么使用 without sharing 执行特定特权操作)。推荐使用 @author、@version、@since、@see、@group 等标签。

/**
 * 此服务类处理关键数据聚合任务。
 * 使用 'without sharing' 以确保访问所有必要记录进行计算,
 * 不受运行用户共享规则的影响。调用此类方法时需谨慎。
 * @author Jane Doe
 * @since 0.1.0
 */
public without sharing class DataAggregationService { }

接口文档化:关注契约而非实现。在主描述中文档化接口的整体目的和契约。对每个方法声明文档化其预期行为、参数和返回值——这为任何实现该接口的类设定期望。@author、@version、@since、@see 均适用。

文档化枚举、方法与构造函数

枚举与方法

枚举文档化:文档化枚举的目的和所代表的概念集。如果枚举常量的名称不够自明,在枚举类型的 ApexDoc 主描述中说明,或直接在常量前的标准注释中说明。隐式方法(values()、valueOf()、name()、ordinal())通常不需要在每个枚举中显式文档化。

/**
 * 一年中可能的季节
 */
public enum Season { WINTER, SPRING, SUMMER, FALL }

方法文档化:使用 @param 标签(每个参数对应一个,描述参数名、目的及类型/内容预期),@return 标签(指定返回值——包括 null 的条件或特定数据结构),@throws 标签(列出所有可能的 checked/unchecked 异常及触发条件——这对于识别错误处理缺口至关重要)。

/**
 * 计算产品列表总价并应用折扣。
 * @param productCodes 唯一产品代码列表——每个必须对应现有 Product2 记录
 * @param discountPercentage 折扣百分比(如10.5为10.5%)——必须在0.0到100.0之间
 * @return 折后总价Decimal——如productCodes为null或空列表返回0.0
 * @throws InvalidArgumentException 如果discountPercentage超出范围
 * @throws ProductNotFoundException 如果任何productCode不匹配现有产品
 */
public Decimal calculateTotalPrice(List<String> productCodes, Decimal discountPercentage) { }

构造函数文档化:与方法的指南相同——描述参数、异常以及构造过程的任何副作用或前置条件。

文档化属性、触发器和注解

属性与注解

属性/变量文档化:文档化构成类公共 API 的 public/global 属性和成员变量。说明属性目的、数据类型(如声明不明显)和重要使用注意事项(如是否只读、默认值)。使用 @see、@since、@deprecated 等标签。

/**
 * 存储操作的最大重试次数。
 * 如未显式设置,默认为3。
 * @since 0.1.1
 */
public Integer maxRetries { get { return maxRetries ?? 3; } set { maxRetries = value; } }

触发器文档化:ApexDoc 没有触发器特定的注释规范——强烈建议将所有业务逻辑委托给单独的 handler 类或触发器框架。但可以使用标准标签如 @since、@see。

关键注解的文档化指南:

注解文档化要点
@AuraEnabled说明是否 cacheable=true、缓存设置的影响
@InvocableMethod元素作为可调用动作的功能;label 和 description 属性
@Future异步运行的影响——单独事务、Governor Limit、callout 行为
@Deprecated必须包含@deprecated 标签:弃用原因和推荐替代方案
@IsTest测试的场景/功能;seeAllData/onInstall 原因
@TestVisible修改可见性的理由
@RestResource描述整体资源及每个HTTP方法的角色

ApexDoc 完整示例

示例

以下是一个包含类、属性、方法、异常及各类标签的完整 ApexDoc 示例:

/**
 * 管理客户账户信息及相关操作。
 * 此类通过'without sharing'绕过用户记录访问权限,以便在批处理类中使用。
 * @author John Developer
 * @since 0.1.0
 * @version 0.3.1
 * @see AccountProcessingBatch
 * @group Account
 */
public without sharing class AccountManager {
    /** 如未指定,新账户的默认区域。 */
    public static final String DEFAULT_REGION = 'North America';

    /** 存储此实例管理的活跃账户数量——使用{@link AccountService}后填充。 */
    @TestVisible
    private Integer activeAccountCount;

    /**
     * 创建具有给定名称和行业的新Account sObject。
     * @param accountName 新账户的期望名称。不能为null或空。
     * @param industry 新账户的行业分类。
     * @return 新创建的Account sObject,ID已填充。
     * @throws AccountManager.AccountException 如果accountName无效或DML操作失败。
     */
    public Account createAccount(String accountName, String industry) {
        if (String.isBlank(accountName))
            throw new AccountException('Account name cannot be blank.');
        Account acc = new Account(Name = accountName, Industry = industry);
        try { insert acc; }
        catch (DmlException e) { throw new AccountException('Failed to create account: ' + e.getMessage()); }
        return acc;
    }

    /** 表示特定于AccountManager操作的异常。 */
    public class AccountException extends Exception {}
}

地理编码服务完整示例(含 @deprecated + @AuraEnabled):

/**
 * 提供地理定位和地址转换服务。
 * @author Dennis Smith
 * @version 0.3.0
 * @since 0.1.0
 */
global with sharing class GeolocationService {
    @AuraEnabled public Decimal latitude;
    @AuraEnabled public Decimal longitude;

    /** @deprecated 0.2.0 使用 {@link #geocodeAddress} 替代——更准确、更健壮。 */
    @Deprecated
    global static Coordinates convertAddressToCoordinates(String fullAddress) { /* ... */ }

    /**
     * 使用健壮的外部地理编码服务将结构化地址编码为精确坐标。
     * @param street 街道地址("123 Main St")
     * @param city 城市("Anytown")
     * @param state 州/省缩写("CA")
     * @param postalCode 邮政编码("90210")
     * @param country 国家名称或代码("USA")
     * @return 包含经纬度的Coordinates对象
     * @throws GeocodingException 如果地址无法编码或外部服务不可用
     * @since 0.2.0
     */
    global static Coordinates geocodeAddress(String street, String city,
        String state, String postalCode, String country) { return new Coordinates(0, 0); }

    global class DeprecatedMethodCalledException extends Exception {}
    global class GeocodingException extends Exception {}
}

@AuraEnabled 方法示例:

/**
 * 检索给定账户的未关闭商机列表,可从Lightning Web Components访问。
 * 如果在与组件交互期间商机集合可能变化,作者需使用{@code refreshApex()}。
 * @param accountId 要检索商机的账户ID
 * @return 未关闭Opportunity记录列表——如未找到或accountId无效则返回空列表
 * @see OpportunitySelector
 */
@AuraEnabled(cacheable=true)
public static List<Opportunity> getOpenOpportunities(Id accountId) { /* ... */ }

ApexDoc 不仅是文档标准——它是创建可维护、可协作、可由 AI 理解的 Salesforce 代码库的关键实践。投入时间编写高质量的 ApexDoc 注释将为你和你的团队带来长期回报。