Apache Maven 是一個用於 Java 和其他基於 JVM 的專案的建置工具。將現有的 Maven 建置遷移到 Gradle 是很常見的。

本指南將透過說明這兩個工具之間的差異和相似之處,並提供可遵循的步驟來簡化流程,協助進行此類遷移。

轉換建置可能會令人感到害怕,但您不必單打獨鬥。如果您遇到問題,可以搜尋我們的文件、在我們的社群論壇發文,或在我們的Slack 頻道上發問。

提出遷移理由

Gradle 和 Maven 之間的主要差異在於靈活性、效能、使用者體驗和相依性管理。

這些面向的視覺化概觀可在 Maven vs Gradle 功能比較 中取得。

自 Gradle 3.0 以來,Gradle 已大量投資於讓 Gradle 建置更快,其功能包括 建置快取編譯避免 和改良的增量 Java 編譯器。即使不使用建置快取,Gradle 現在對於絕大多數專案來說都比 Maven 快 2-10 倍。深入的效能比較和從 Maven 切換到 Gradle 的商業案例可在此處 取得

一般準則

Gradle 和 Maven 對於如何建置專案有根本上不同的看法。Gradle 提供一個彈性且可延伸的建置模型,將實際工作委派給執行任務圖形。Maven 使用固定線性階段模型,您可以將目標(執行工作的項目)附加到該模型。這可能會讓在兩者之間進行移轉看起來令人望而生畏,但移轉可能會出乎意料地容易,因為 Gradle 遵循許多與 Maven 相同的慣例,例如 標準專案結構,而且其相依性管理運作方式類似。

在此,我們列出一系列步驟供您遵循,有助於促進任何 Maven 建置移轉至 Gradle

並排保留舊的 Maven 建置和新的 Gradle 建置。您知道 Maven 建置有效,因此您應該保留它,直到您確信 Gradle 建置產生所有相同的成品。這也表示使用者可以在不建立原始碼樹的新副本的情況下嘗試 Gradle 建置。
  1. 為 Maven 建置建立建置掃描.

    建置掃描將讓您更容易視覺化現有 Maven 建置中發生的事情。對於 Maven 建置,您將能夠看到專案結構、正在使用的外掛、建置步驟的時間表等等。將其保留在手邊,以便在轉換專案時將其與 Gradle 建置掃描進行比較。

  2. 開發一種機制來驗證兩個建置產生相同的成品。

    這是確保部署和測試不會中斷的重要步驟。即使是微小的變更,例如 JAR 中的明細檔內容,都可能造成問題。如果 Gradle 建置產生與 Maven 建置相同的輸出,這將讓您有信心進行切換,並讓您更容易實作將帶來最大好處的變更。

    這並不表示您需要在每個階段驗證每個成品,儘管這麼做可以幫助您快速找出問題的來源。您應該專注於關鍵輸出,例如最終報告和已發布或部署的成品。

    您需要考量 Gradle 與 Maven 產生的建置輸出中一些固有的差異。產生的 POM 只會包含使用時所需的資訊,而且會針對該情境正確使用 <compile><runtime> 範圍。您也可能會看到檔案於封存檔中的順序,以及類別路徑中檔案的順序有所不同。大多數的差異都很小,但找出它們並驗證它們是可以接受的,這是有價值的。

  3. 執行自動轉換.

    這將建立您所需的所有 Gradle 建置檔案,即使是 多模組建置 也是如此。對於較簡單的 Maven 專案,Gradle 建置會準備好執行!

  4. 為 Gradle 建置建立建置掃描.

    建置掃描將讓您更容易視覺化建置中發生的事。對於 Gradle 建置,您將能夠看到專案結構、相依性(常規和專案間)、正在使用的外掛,以及建置的主控台輸出。

    您的建置可能在此時失敗,但沒關係;掃描仍然會執行。將 Gradle 建置的建置掃描與 Maven 建置的建置掃描進行比較,並繼續往下查看此清單以排除故障。

    我們建議您在遷移期間定期產生建置掃描,以幫助您找出並排除問題。如果您願意,您也可以使用 Gradle 建置掃描找出 改善建置效能 的機會。

  5. 驗證您的相依性並修復任何問題.

  6. 設定整合和功能測試.

    許多測試可以透過設定額外的來源集來輕鬆遷移。如果您使用的是第三方程式庫,例如 FitNesse,請查看 Gradle 外掛入口網站 上是否有合適的社群外掛可用。

  7. 以 Gradle 等效項取代 Maven 外掛。

    對於 熱門外掛,Gradle 通常有您可以使用的等效外掛。您可能也會發現您可以 以內建 Gradle 功能取代外掛。作為最後的手段,您可能需要透過您自己的自訂外掛和任務類型來 重新實作 Maven 外掛

    本章節的其餘部分將更詳細地探討從 Maven 遷移至 Gradle 的建置特定面向。

了解建置生命週期

Maven 建置基於 建置生命週期 的概念,其中包含一組固定階段。這對遷移至 Gradle 的使用者來說可能是一項挑戰,因為建置生命週期是一個 新概念。儘管了解 Gradle 建置如何符合 初始化設定執行 階段的結構非常重要,但 Gradle 提供了一個輔助功能,可以模擬 Maven 的階段:生命週期任務

此功能允許您透過建立不執行動作的任務來定義自己的「生命週期」,這些任務僅依賴於您有興趣的任務。為了讓 Maven 使用者更容易轉換至 Gradle,基本外掛(由所有 JVM 語言外掛套用,例如 Java 函式庫外掛)提供了一組與主要 Maven 階段對應的生命週期任務。

以下是部分主要 Maven 階段及其對應的 Gradle 任務清單

clean

使用基本外掛提供的 clean 任務。

compile

使用 Java 外掛和其他 JVM 語言外掛提供的 classes 任務。這會編譯所有語言的所有原始檔的所有類別,並透過 processResources 任務執行 資源篩選

test

使用 Java 外掛提供的 test 任務。它會執行單元測試,更具體地說,是組成 test 原始檔組 的測試。

package

使用基本外掛提供的 assemble 任務。這會建置專案的適當套件;例如,Java 函式庫的 JAR 或傳統 Java 網路應用程式的 WAR。

verify

使用基本外掛提供的 check 任務。這會執行附加到其上的所有驗證任務,通常包括單元測試、任何靜態分析任務(例如 Checkstyle)和其他任務。如果您要包含整合測試,您必須 手動設定這些測試

install

使用 Maven 發行外掛提供的 publishToMavenLocal 任務。

請注意,Gradle 建置不需要您「安裝」人工製品,因為您可以存取更適當的功能,例如 專案間相依性複合建置。您應該只使用 publishToMavenLocal 來與 Maven 建置進行互操作。

Gradle 也允許您根據 宣告存放庫 區段中所述,針對本機 Maven 快取解析相依性。

部署

使用 Maven 發佈外掛程式 所提供的 publish 任務,如果您建置使用較舊的 Maven 外掛程式(ID:maven),請務必從中切換。這會將您的套件發佈到所有已設定的發佈存放庫。還有一些任務允許您發佈到單一存放庫,即使已定義多個存放庫也是如此。

請注意,Maven 發佈外掛程式預設不會發佈原始碼和 Javadoc JAR,但這可以輕鬆啟用,如 建置 java 專案指南 中所述。

執行自動轉換

Gradle 的 init 任務 通常用於建立新的架構專案,但您也可以使用它自動將現有的 Maven 建置轉換為 Gradle。一旦 Gradle 安裝到您的系統,您所要做的就是執行指令

> gradle init

從根專案目錄。這包括剖析現有的 POM 並產生對應的 Gradle 建置指令碼。如果您要移轉 多專案建置,Gradle 也會建立設定指令碼。

您會發現新的 Gradle 建置包含下列內容

  • POM 中指定的所有自訂存放庫

  • 您的外部和專案間相依性

  • 建置專案的適當外掛程式(僅限於一個或多個 Maven 發佈JavaWar 外掛程式)

請參閱 建置初始化外掛程式章節,以取得自動轉換功能的完整清單。

需要記住的一件事是,組件不會自動轉換。此額外轉換需要一些手動工作。選項包括

如果您的 Maven 建置沒有很多外掛或自訂步驟,您可以簡單地執行

> gradle build

在遷移完成後。這將執行測試並自動產生所需的成品。

遷移相依性

Gradle 的相依性管理系統比 Maven 的更靈活,但它仍支援相同的概念,例如儲存庫、宣告的相依性、範圍(Gradle 中的相依性組態)和遞移相依性。事實上,Gradle 與相容 Maven 的儲存庫搭配運作,這使得遷移您的相依性變得容易。

這兩個工具之間一個顯著的差異在於它們管理版本衝突的方式。Maven 使用「最接近」的比對演算法,而 Gradle 選擇最新的。不過不用擔心,您可以控制選擇哪些版本,如 管理遞移相依性 中所述。

在以下各節中,我們將展示如何遷移 Maven 建置相依性管理資訊中最常見的元素。

宣告相依性

Gradle 使用與 Maven 相同的相依性識別元件:群組 ID、成品 ID 和版本。它也支援分類器。您需要做的就是將相依性的識別資訊替換為 Gradle 的語法,這在 宣告相依性 章節中有所說明。

例如,考慮這個對 Log4J 的 Maven 風格相依性

<dependencies>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
    </dependency>
</dependencies>

這個相依性在 Gradle 建置指令碼中看起來像這樣

build.gradle.kts
dependencies {
    implementation("log4j:log4j:1.2.12")  (1)
}
build.gradle
dependencies {
    implementation 'log4j:log4j:1.2.12'  (1)
}
1 將 Log4J 的版本 1.2.12 附加到 implementation 組態(範圍)

字串識別碼採用 groupIdartifactIdversion 的 Maven 值,儘管 Gradle 將它們稱為 groupmoduleversion

上述範例引發了一個明顯的問題:什麼是 implementation 組態?它是 Java 外掛 提供的標準相依性組態之一,通常用作 Maven 預設 compile 範圍的替代品。

Maven 的範圍和 Gradle 的標準組態之間的幾個差異歸結為 Gradle 區分建置模組所需的相依性和建置依賴於它的模組所需的相依性。Maven 沒有這樣的區別,因此已發佈的 POM 通常包含使用者實際上不需要的相依性。

以下是 Maven 的主要相依性範圍以及您應該如何處理它們的遷移

compile

Gradle 有兩個組態可以用來取代 compile 範圍:implementationapi。前者可用於任何套用 Java 外掛的專案,而 api 僅可用於特別套用 Java 函式庫外掛 的專案。

在多數情況下,你應該只使用 implementation 設定,特別是如果你正在建構應用程式或網頁應用程式時。但如果你正在建構函式庫,你可以從 建構 Java 函式庫 章節中瞭解哪些相依性應該使用 api 宣告。上述連結的 Java 函式庫外掛程式章節中提供了更多關於 apiimplementation 之間差異的資訊。

執行時期

使用 runtimeOnly 設定。

test

Gradle 區分需要用來編譯專案測試的相依性,以及只需要用來執行測試的相依性。

用於測試編譯的相依性應該針對 testImplementation 設定宣告。而只需要用於執行測試的相依性則應該使用 testRuntimeOnly

已提供

使用 compileOnly 設定。

請注意,War 外掛程式 會新增 providedCompileprovidedRuntime 相依性設定。這些設定的行為與 compileOnly 稍微不同,它們只會確保這些相依性不會封裝在 WAR 檔案中。然而,這些相依性會包含在執行時期和測試執行時期類別路徑中,因此如果你需要這種行為,請使用這些設定。

匯入

import 範圍主要用於 <dependencyManagement> 區塊中,並且僅適用於僅 POM 的出版品。請閱讀 使用物料清單 章節,以瞭解如何複製此行為的更多資訊。

你也可以對僅 POM 的出版品指定常規相依性。在這種情況下,在該 POM 中宣告的相依性會被視為建置的正常傳遞相依性。

例如,假設你想要為你的測試使用 groovy-all POM。它是一個僅 POM 的出版品,其相依性列在 <dependencies> 區塊中。Gradle 建置中的適當設定如下所示

build.gradle.kts
dependencies {
    testImplementation("org.codehaus.groovy:groovy-all:2.5.4")
}
build.gradle
dependencies {
    testImplementation 'org.codehaus.groovy:groovy-all:2.5.4'
}

這樣做的結果是,groovy-all POM 中的所有 compileruntime 範圍相依性都會新增到測試執行時期類別路徑中,而只有 compile 範圍相依性會新增到測試編譯類別路徑中。具有其他範圍的相依性將會被忽略。

宣告儲存庫

Gradle 允許您從任何相容於 Maven 或 Ivy 的儲存庫中擷取已宣告的相依性。與 Maven 不同,它沒有預設儲存庫,因此您必須至少宣告一個。若要讓您的 Gradle 建置具有與 Maven 建置相同的行為,請在您的 Gradle 建置中設定 Maven Central,如下所示

build.gradle.kts
repositories {
    mavenCentral()
}
build.gradle
repositories {
    mavenCentral()
}

您也可以使用 repositories {} 區塊來設定自訂儲存庫,如 儲存庫類型 章節所述。

最後,Gradle 允許您針對 本機 Maven 快取/儲存庫 解析相依性。這有助於 Gradle 建置與 Maven 建置互通,但若您不需要這種互通性,則不應使用此技術。如果您想要透過檔案系統分享已發布的成品,請考慮設定一個 自訂 Maven 儲存庫,網址為 file://

您可能也有興趣瞭解 Gradle 自有的 相依性快取,其行為比 Maven 的更可靠,且可安全地由多個同時進行的 Gradle 程序使用。

控制相依性版本

傳遞相依性的存在表示您很容易在您的相依性圖中得到多個相同相依性的版本。預設情況下,Gradle 會在圖中挑選最新版本的相依性,但這並不總是正確的解決方案。這就是為什麼它提供多種機制來控制解析哪個版本的特定相依性。

在每個專案的基礎上,您可以使用

控制傳遞相依性 章節中列出了更多專門選項。

如果您希望確保多專案建置中所有專案的版本一致性,類似於 Maven 中的 <dependencyManagement> 區塊運作的方式,您可以使用 Java Platform Plugin。這允許您宣告一組可套用至多個專案的相依性約束。您甚至可以將平台發布為 Maven BOM 或使用 Gradle 的元資料格式。請參閱外掛程式頁面,以取得更多關於如何這樣做的資訊,特別是 使用平台 的區段,以了解如何將平台套用至同一建置中的其他專案。

排除傳遞相依性

Maven 建置使用排除來將不需要的相依性(或不需要的相依性版本)排除在相依性圖表之外。您可以在 Gradle 中執行相同的動作,但這不一定是最正確的作法。Gradle 提供其他選項,可能更適合特定情況,因此您真的需要了解排除的原因,才能適當地進行移轉。

如果您想因為與版本無關的原因而排除相依性,請查看 排除傳遞相依性 的區段。它會說明如何將排除附加至整個組態(通常是最適當的解決方案)或相依性。您甚至可以輕鬆地將排除套用至所有組態。

如果您更想控制實際解析的相依性版本,請參閱前一區段。

處理選用相依性

您可能會遇到兩種與選用相依性相關的情況

  • 您的某些傳遞相依性宣告為選用

  • 您想在專案發布的 POM 中宣告某些直接相依性為選用

對於第一個情境,Gradle 的行為與 Maven 相同,只會忽略宣告為選用的任何傳遞相依性。它們不會被解析,也不會對版本選擇造成影響,如果相同的相依性出現在相依性圖表中的其他地方作為非選用。

至於將相依性發布為選用,Gradle 提供一個稱為 功能變異 的更豐富模型,這將讓您宣告您的程式庫提供的「選用功能」。

使用物料清單 (BOM)

Maven 允許您透過在封裝類型為 pom 的 POM 檔案的 <dependencyManagement> 區段中定義相依性,來分享相依性限制。然後可以將這種特殊類型的 POM (BOM) 匯入其他 POM,以便在您的專案中擁有相容的程式庫版本。

Gradle 可以使用此類 BOM 來達成相同目的,使用基於 platform()enforcedPlatform() 方法的特殊相依性語法。您只需以一般方式宣告相依性,但將相依性識別碼包覆在適當的方法中,如下面的範例所示,它「匯入」Spring Boot 相依性 BOM

build.gradle.kts
dependencies {
    implementation(platform("org.springframework.boot:spring-boot-dependencies:1.5.8.RELEASE"))  (1)

    implementation("com.google.code.gson:gson")  (2)
    implementation("dom4j:dom4j")
}
build.gradle
dependencies {
    implementation platform('org.springframework.boot:spring-boot-dependencies:1.5.8.RELEASE') (1)

    implementation 'com.google.code.gson:gson' (2)
    implementation 'dom4j:dom4j'
}
1 套用 Spring Boot 相依性 BOM
2 新增相依性,其版本由該 BOM 定義

您可以在 從 Maven BOM 匯入版本建議 的區段中進一步了解此功能,以及 platform()enforcedPlatform() 之間的差異。

您可以使用此功能將任何相依性的 POM 中的 <dependencyManagement> 資訊套用到 Gradle 建置,即使那些封裝類型不是 pom 的相依性也是如此。platform()enforcedPlatform() 都會忽略在 <dependencies> 區塊中宣告的任何相依性。

移轉多模組建置 (專案聚合)

Maven 的多模組建置可以順利對應到 Gradle 的 多專案建置。請嘗試對應的 範例,以了解如何設定基本的多專案 Gradle 建置。

若要移轉多模組 Maven 建置,只需執行下列步驟

  1. 建立與根 POM 的 <modules> 區塊相符的設定指令碼。

    例如,這個 <modules> 區塊

    <modules>
        <module>simple-weather</module>
        <module>simple-webapp</module>
    </modules>

    可以透過將下列程式碼行新增到設定指令碼中來移轉

    settings.gradle.kts
    rootProject.name = "simple-multi-module"  (1)
    
    include("simple-weather", "simple-webapp")  (2)
    settings.gradle
    rootProject.name = 'simple-multi-module'  (1)
    
    include 'simple-weather', 'simple-webapp'  (2)
    1 設定整體專案名稱
    2 將兩個子專案設定為此組建的一部分
    gradle 專案 的輸出
    > gradle projects
    
    ------------------------------------------------------------
    Root project 'simple-multi-module'
    ------------------------------------------------------------
    
    Root project 'simple-multi-module'
    +--- Project ':simple-weather'
    \--- Project ':simple-webapp'
    
    To see a list of the tasks of a project, run gradle <project-path>:tasks
    For example, try running gradle :simple-weather:tasks
  2. 專案相依性 取代跨模組相依性。

  3. 慣例外掛程式 複製專案繼承。

    這基本上包括建立一個根專案組建指令碼,將共用設定注入到適當的子專案中。

在專案間共用版本

如果您想複製 Maven 模式,在根 POM 檔案的 dependencyManagement 區段中宣告相依性版本,最好的方法是利用 java-platform 外掛程式。您需要為此新增一個專門的專案,並在組建的常規專案中使用它。請參閱 文件,以取得此模式的更多詳細資料。

移轉 Maven 設定檔和屬性

Maven 允許您使用各種屬性參數化組建。有些是專案模型的唯讀屬性,其他則是在 POM 中由使用者定義的。它甚至允許您將系統屬性視為專案屬性。

Gradle 有類似的專案屬性系統,儘管它區分了這些屬性和系統屬性。例如,您可以在下列位置定義屬性:

  • 組建指令碼

  • 根專案目錄中的 gradle.properties 檔案

  • $HOME/.gradle 目錄中的 gradle.properties 檔案

這些不是唯一的選項,因此如果您有興趣進一步瞭解如何以及可以在哪裡定義屬性,請查看 組建環境 章節。

您需要了解的一項重要行為是,當同一個屬性同時在組建指令碼和其中一個外部屬性檔案中定義時會發生什麼事:組建指令碼值優先。始終如此。幸運的是,您可以模仿設定檔的概念,以提供可覆寫的預設值。

這讓我們了解 Maven 設定檔。這些是一種根據環境、目標平台或任何其他類似因素啟用和停用不同設定的方式。在邏輯上,它們只不過是有限的 if 陳述式。由於 Gradle 有更強大的方式來宣告條件,因此它不需要正式支援設定檔(除了相依性的 POM 之外)。您可以輕鬆地將條件與次要組建指令碼結合,以取得相同的行為,您將會看到。

假設您有不同的部署設定,取決於環境:本機開發(預設)、測試環境和生產環境。若要新增類似設定檔的行為,請先在專案根目錄中為每個環境建立建置指令碼:profile-default.gradleprofile-test.gradleprofile-prod.gradle。然後,您可以根據您自己選擇的 專案屬性,有條件地套用其中一個設定檔指令碼。

下列範例示範使用稱為 buildProfile 的專案屬性,以及只初始化稱為 message額外專案屬性 的設定檔指令碼的基本技巧

build.gradle.kts
val buildProfile: String? by project  (1)

apply(from = "profile-${buildProfile ?: "default"}.gradle.kts")  (2)

tasks.register("greeting") {
    // Store the message into a variable, because referencing extras from the task action
    // is not compatible with the configuration cache.
    val message = project.extra["message"]
    doLast {
        println(message)  (3)
    }
}
profile-default.gradle.kts
val message by extra("foobar")  (4)
profile-test.gradle.kts
val message by extra("testing 1 2 3")  (4)
profile-prod.gradle.kts
val message by extra("Hello, world!")  (4)
build.gradle
if (!hasProperty('buildProfile')) ext.buildProfile = 'default'  (1)

apply from: "profile-${buildProfile}.gradle"  (2)

tasks.register('greeting') {
    // Store the message into a variable, because referencing extras from the task action
    // is not compatible with the configuration cache.
    def message = project.message
    doLast {
        println message  (3)
    }
}
profile-default.gradle
ext.message = 'foobar'  (4)
profile-test.gradle
ext.message = 'testing 1 2 3'  (4)
profile-prod.gradle
ext.message = 'Hello, world!'  (4)
1 檢查 (Groovy) 或繫結 (Kotlin) buildProfile 專案屬性的存在
2 套用適當的設定檔指令碼,使用指令碼檔名中的 buildProfile
3 列印 message 額外專案屬性的值
4 初始化 message 額外專案屬性,其值可以在主建置指令碼中使用

有了這個設定,您可以透過傳遞專案屬性的值來啟用其中一個設定檔,在本例中為 buildProfile

gradle greeting 的輸出
> gradle greeting
foobar
gradle -PbuildProfile=test greeting 的輸出
> gradle -PbuildProfile=test greeting
testing 1 2 3

您不限於檢查專案屬性。您也可以檢查環境變數、JDK 版本、執行建置的作業系統,或任何您能想到的其他內容。

需要注意的一件事是,高階條件陳述式會讓建置更難理解和維護,類似於它們使物件導向程式碼複雜化的方式。設定檔也適用相同的原則。Gradle 為您提供了許多更好的方法來避免 Maven 經常需要的廣泛使用設定檔,例如透過設定多個彼此為變體的任務。請參閱 Maven 發佈外掛程式 建立的 publishPubNamePublicationToRepoNameRepository 任務。

若要深入探討在 Gradle 中使用 Maven 設定檔,請直接參閱 這篇部落格文章

過濾資源

Maven 有個稱為 process-resources 的階段,預設會將目標 resources:resources 與它連結。這讓建置作者有機會對各種檔案執行變數替換,例如網頁資源、封裝的屬性檔案等。

Gradle 的 Java 外掛提供一個 processResources 任務來執行相同的工作。這個 ProcessResources 任務會將檔案從設定的資源目錄(預設為 src/main/resources)複製到輸出目錄。而且就像任何 ProcessResourcesCopy 任務一樣,你可以設定它來執行 檔案過濾重新命名內容過濾

以下是一個範例設定,它將原始檔案視為 Groovy SimpleTemplateEngine 範本,並提供 versionbuildNumber 屬性給這些範本

build.gradle.kts
tasks {
    processResources {
        expand("version" to version, "buildNumber" to currentBuildNumber)
    }
}
build.gradle
processResources {
    expand(version: version, buildNumber: currentBuildNumber)
}

請參閱 CopySpec 的 API 文件,以查看所有可用的選項。

設定整合測試

許多 Maven 建置會納入某種形式的整合測試,Maven 會透過額外的階段集來支援這項功能:pre-integration-testintegration-testpost-integration-testverify。它也會使用 Failsafe 外掛取代 Surefire,這樣失敗的整合測試就不會自動導致建置失敗(因為你可能需要清理資源,例如正在執行的應用程式伺服器)。

這種行為很容易使用來源集在 Gradle 中複製,如我們在 Java 和 JVM 專案的測試 章節中所說明。然後你可以設定一個清理任務,例如關閉測試伺服器,以在整合測試之後始終執行,無論它們是否成功或失敗,方法是使用 Task.finalizedBy()

如果你真的不希望整合測試導致建置失敗,那麼你可以使用 Test.ignoreFailures 設定,如 Java 測試章節的 測試執行 部分所述。

來源集也讓你對整合測試的原始檔案放置位置有很大的彈性。你可以輕鬆地將它們放在與單元測試相同的目錄中,或者更理想的做法是放在一個獨立的來源目錄中,例如 src/integTest/java。若要支援其他類型的測試,只需新增更多來源集和 測試 任務即可。

移轉常見外掛

Maven 和 Gradle 共用一種透過外掛擴充建置的常見方法。儘管外掛系統在表面下非常不同,但它們共用許多基於功能的外掛,例如

  • Shade/Shadow

  • Jetty

  • Checkstyle

  • JaCoCo

  • AntRun(請參閱下方)

這為何重要?因為許多外掛依賴於標準 Java 慣例,移轉只是複製 Maven 外掛在 Gradle 中的組態問題。舉例來說,以下是簡單的 Maven Checkstyle 外掛組態

...
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-checkstyle-plugin</artifactId>
  <version>2.17</version>
  <executions>
    <execution>
      <id>validate</id>
      <phase>validate</phase>
      <configuration>
        <configLocation>checkstyle.xml</configLocation>
        <encoding>UTF-8</encoding>
        <consoleOutput>true</consoleOutput>
        <failsOnError>true</failsOnError>
        <linkXRef>false</linkXRef>
      </configuration>
      <goals>
        <goal>check</goal>
      </goals>
    </execution>
  </executions>
</plugin>
...

移轉到 Gradle 時,組態區塊外的所有內容都可以安全地忽略。在此情況下,對應的 Gradle 組態如下

build.gradle.kts
checkstyle {
    config = resources.text.fromFile("checkstyle.xml", "UTF-8")
    isShowViolations = true
    isIgnoreFailures = false
}
build.gradle
checkstyle {
    config = resources.text.fromFile('checkstyle.xml', 'UTF-8')
    showViolations = true
    ignoreFailures = false
}

Checkstyle 工作會自動新增為 check 工作的相依項,其中也包括 test。如果您要確保 Checkstyle 在測試前執行,請使用 mustRunAfter(…​) 方法指定順序

build.gradle.kts
tasks {
    test {
        mustRunAfter(checkstyleMain, checkstyleTest)
    }
}
build.gradle
test.mustRunAfter checkstyleMain, checkstyleTest

您會看到,Gradle 組態通常比 Maven 等效組態短很多。您也有更靈活的執行模型,因為您不再受限於 Maven 的固定階段。

在從 Maven 移轉專案時,別忘了來源組。這些來源組通常提供比 Maven 更優雅的解決方案來處理整合測試或產生來源,因此您應該將它們納入您的移轉計畫。

Ant 目標

許多 Maven 建置依賴於 AntRun 外掛,以自訂建置,而不會實作自訂 Maven 外掛的負擔。Gradle 沒有等效外掛,因為 Ant 是 Gradle 建置中的一等公民,透過 ant 物件。例如,您可以像這樣使用 Ant 的 Echo 工作

build.gradle.kts
tasks.register("sayHello") {
    doLast {
        ant.withGroovyBuilder {
            "echo"("message" to "Hello!")
        }
    }
}
build.gradle
tasks.register('sayHello') {
    doLast {
        ant.echo message: 'Hello!'
    }
}

甚至 Ant 屬性和檔案集也原生支援。如需深入了解,請參閱 從 Gradle 使用 Ant

建立 自訂工作類型 來取代 Ant 為您執行的作業可能會更簡單、更乾淨。然後,您可以更輕易地受益於 增量建置 和其他有用的 Gradle 功能。

了解您不需要哪些外掛

值得注意的是,Gradle 建置通常比 Maven 的建置更容易擴充和自訂。在此脈絡中,表示您可能不需要 Gradle 外掛程式來取代 Maven 的外掛程式。例如,Maven Enforcer 外掛程式讓您可以控制相依性版本和環境因素,但這些內容可以在一般的 Gradle 建置指令碼中輕鬆設定。

處理不常見和自訂外掛程式

您可能會遇到在 Gradle 中沒有對應項的 Maven 外掛程式,特別是如果您或組織中的某人撰寫了自訂外掛程式時。此類案例仰賴您了解 Gradle(和潛在的 Maven)運作方式,因為您通常必須撰寫自己的外掛程式。

在遷移目的方面,有兩種主要的 Maven 外掛程式類型

  • 使用 Maven 專案物件的類型。

  • 不使用 Maven 專案物件的類型。

這點為何重要?因為如果您使用後者的其中一個類型,您可以輕易地將其重新實作為 自訂 Gradle 任務類型。只要定義與 mojo 參數對應的任務輸入和輸出,並將執行邏輯轉換為任務動作即可。

如果外掛程式依賴於 Maven 專案,則您必須重新撰寫它。不要從考慮 Maven 外掛程式如何運作開始,而是觀察它嘗試解決的問題。然後嘗試找出如何在 Gradle 中解決該問題。您可能會發現這兩個建置模型有足夠的差異,以至於將 Maven 外掛程式程式碼「轉錄」到 Gradle 外掛程式中不會有效。好處是,由於 Gradle 具有更豐富的建置模型和 API,因此外掛程式可能會比原始 Maven 外掛程式更容易撰寫。

如果您確實需要透過建置指令碼或外掛程式實作自訂邏輯,請查看與外掛程式開發相關的指南。此外,務必熟悉 Gradle 的Groovy DSL 參考,其中提供了您將使用之 API 的完整文件。它詳細說明了標準設定區塊(以及它們所備份的物件)、系統中的核心類型(ProjectTask 等)以及標準任務類型集合。主要進入點是Project介面,因為它是備份建置指令碼的頂層物件。

進一步閱讀

本章節涵蓋了將 Maven 建置移轉到 Gradle 的主要主題。剩下的只有一些在移轉期間或移轉後可能會有用的其他領域

最後,本指南僅介紹了 Gradle 的一些功能,我們鼓勵您從使用者手冊的其他章節和我們的逐步範例中瞭解其餘功能。