﻿# 如何在 Spring Boot 產製專案的 API 文件並自動合併到 site 文件站台

我前陣子分享過 [如何讓 Spring Boot 與 Maven 專案成功產製文件站台](/post/2021/08/13/Spring-Boot-Maven-site-phase) 文章，當時由於 Spring Boot 預設的 `maven-site-plugin v3.3` 版本有問題，導致無法成功產生 site 文件站台，因此我們必須明確定義 `maven-site-plugin`版本定義才正常。這篇文章我打算分享如何在 site 文件站台上加入 Javadoc 產生的 API 文件，更加豐富我們專案的開發文件！

首先要提醒大家的地方是，JDK 11 與 JDK 8 所附的 `javadoc` 工具有些不太一樣，所以你要設定正確的 `JAVA_HOME` 與 `PATH` 才能讓團隊或 CI 的時候產生相同規格的文件檔案！

1.  查詢 `maven-javadoc-plugin` 版本
    
    由於 Spring Boot 本身就包含了 [Apache Maven Javadoc Plugin](https://maven.apache.org/plugins/maven-javadoc-plugin/index.html) 外掛套件，但是非常的不明顯，必須透過以下命令取得完整的 POM 資訊，才能得知這件事：
    
    ```bash
    mvn help:effective-pom
    ```
    
    ```xml
    <plugin>
        <artifactId>maven-javadoc-plugin</artifactId>
        <version>3.2.0</version>
    </plugin>
    ```
    
2.  記得設定 `maven-site-plugin` Plugin 到 `pom.xml` 的 `build > plugins` 設定中
    
    ```xml
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-site-plugin</artifactId>
        <version>3.9.1</version>
    </plugin>
    ```
    
    如果要更精細的定義 JavaDoc 的行為，可以參考以下[設定值](https://maven.apache.org/plugins-archives/maven-javadoc-plugin-2.10.4/fix-mojo.html)：
    
    ```xml
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-javadoc-plugin</artifactId>
        <version>3.3.0</version>
        <configuration>
            <defaultAuthor>Duotify Team</defaultAuthor>
            <fixTags>author,param,return,throws,link</fixTags>
            <level>private</level>
        </configuration>
    </plugin>
    ```
    
    > 我對於 [javadoc:fix](https://maven.apache.org/plugins-archives/maven-javadoc-plugin-2.10.4/fix-mojo.html) 文件上的 Optional Parameters 理解好久，最後才嘗試出來是向上面這樣，必須設定在 `build > plugins` 區段內，以及設定在 `<configuration>` 裡面才有效果！
    
3.  加入 `maven-javadoc-plugin` Plugin 到 `pom.xml` 的 `reporting > plugins` 設定中
    
    ```xml
    <reporting>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
                <version>3.3.0</version>
                <configuration>
                    <show>private</show>
                </configuration>
                <reportSets>
                    <reportSet>
                        <id>default</id>
                        <reports>
                            <report>javadoc</report>
                            <!-- <report>test-javadoc</report> -->
                        </reports>
                    </reportSet>
                </reportSets>
            </plugin>
        </plugins>
    </reporting>
    ```
    
    > 因為我們有用 [Lombok](https://projectlombok.org/) 來自動產生 Getter/Setter 方法，所以我們會需要連 `private` 成員也都產生文件！
    

### 預設 Spring Boot 無法產生報表的原因

我第一次在設定 `maven-javadoc-plugin` Plugin 的時候，覺得網路上找到的資料都很混亂，官網的範例也非常多，琳瑯滿目的，不知道要參考哪一個，其中最簡單的設定，其實是以下這個：

```xml
<reporting>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-javadoc-plugin</artifactId>
    </plugin>
  </plugins>
</reporting>
```

不過，使用 `maven-javadoc-plugin` 的預設值，有很大的機會將無法產生報告，並出現 `Error generating maven-javadoc-plugin:3.2.0:test-aggregate-no-fork report` 錯誤，詳細的錯誤訊息如下：

```log
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-site-plugin:3.9.1:site (default-site) on project demo1: Error generating maven-javadoc-plugin:3.2.0:test-aggregate-no-fork report:
[ERROR] Exit code: 1 - javadoc: error - No public or protected classes found to document.
[ERROR]
[ERROR] Command line was: cmd.exe /X /C ""C:\Program Files\AdoptOpenJDK\jdk-11.0.11.9-hotspot\bin\javadoc.exe" @options @packages"
[ERROR]
[ERROR] Refer to the generated Javadoc files in 'g:\Projects\demo1\target\site\testapidocs' dir.
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
```

![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/76facf50a596e4013348-130061098-d005acfc-c4e6-48c3-8d32-a4eab8fa5790.png)

我第一次看到的時候，其實很難理解為什麼會出這個問題，而且後來有發現，使用 `mvn javadoc:javadoc` 是可以成功產生文件的，但是用 `mvn site` 就是不行，所以我沒辦法自動將 Javadoc 產製的 API 文件整合到 site 文件網站中。

如果你從錯誤訊息內容中抽絲剝繭，可以發現這個問題「可能」跟 `test` 有關係，因為他無法產生 Javadoc 檔案到 `target\site\testapidocs` 目錄中。如果再搭配著看 `No public or protected classes found to document` 這段，組合在一起才是有意義的。原來是因為在我們的**測試程式**中，找不到任何一個**公開**(public)的或**受保護**(protected)的**類別**(class)，因此無法產生任何一份測試類別的 Javadoc 文件。

所以解決方法有兩種：

1.  設定 `<reportSets>` 並僅設定針對 `javadoc` 報表進行輸出
    
    ```xml
    <reporting>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
                <reportSets>
                    <reportSet>
                        <reports>
                            <report>javadoc</report>
                            <!-- <report>test-javadoc</report> -->
                        </reports>
                    </reportSet>
                </reportSets>
            </plugin>
        </plugins>
    </reporting>
    ```
    
2.  調整 `maven-javadoc-plugin` 的 `show` 參數設定
    
    這裡的 `package` 所代表的，就是同一個 package 內的類別都可以存取的範圍，在 [Java Access Modifiers](https://web.archive.org/web/20250209160749/https://www.javatpoint.com/access-modifiers) 文件中，被定義為 `Default` 層級。只要你切換為 `package` 就可以正確輸出測試程式的 API 文件。
    
    ```xml
    <reporting>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
                <configuration>
                  <show>package</show>
                </configuration>
            </plugin>
        </plugins>
    </reporting>
    ```
    
    上述 `<show>package</show>` 預設為 `protected`，代表可以產生所有 `public` 與 `protected` 的類別與成員。如果你修改成 `public` 的話，就會僅產生 `public` 公開的類別與成員。設定成 `private` 的話，意味著能產生所有存取等級(access level)的類別與成員。我上述的例子是用 `package`，這意味著只要類別**沒有明確定義**為 `private` 的話，就會也會產生 API 文件。
    

### 後記

Java 世界的 [Javadoc](https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html) 工具比我想像的還強大許多，不但功能相當完整，第三方的整合工具也相當全面，像是 Spring Boot 跟 Maven 就與 Javadoc 整合的相當完美。不過相對的，當遇到問題的時候，解決問題的複雜度自然也會高出一些，而且網路上的資訊相當亂，比較難有完整且全面的文件可以帶領初學者上手。

### 相關連結

-   [Apache Maven Javadoc Plugin – Introduction](https://maven.apache.org/plugins/maven-javadoc-plugin/index.html)
    -   [Frequently Asked Questions](http://maven.apache.org/plugins/maven-javadoc-plugin/faq.html#Where_in_the_pom.xml_do_I_configure_the_Javadoc_Plugin)
-   [Maven – Guide to Configuring Plug-ins](http://maven.apache.org/guides/mini/guide-configuring-plugins.html)
    -   [Configuring Reporting Plugins](http://maven.apache.org/guides/mini/guide-configuring-plugins.html#configuring-reporting-plugins)
-   [How to Write Doc Comments for the Javadoc Tool](https://www.oracle.com/tw/technical-resources/articles/java/javadoc-tool.html)
