本頁總結了 Gradle 報告的不同任務(或一般工作)驗證問題,並提供修正指南。

cacheable 註解的無效使用

此錯誤表示您已在非工件轉換的事物上使用 @CacheableTransform 註解類型,或在非 Task 的事物上使用 @CacheableTask

解決方案是移除註解。

對於任務,要使用的註解是 @CacheableTask。對於工件轉換,要使用的註解是 @CacheableTransform

缺少正規化註解

每當任務或工件轉換可快取,且檔案或檔案集合輸入屬性未宣告應如何正規化時,就會發生此錯誤。 正規化告訴 Gradle,例如,輸入檔案的絕對路徑是否重要,或者只有內容是否相關。 如果您未宣告正規化策略,則任務的輸出無法在機器之間或同一機器上的不同位置之間重複使用。 簡而言之,沒有正規化,快取非常無效。

要修正此問題,您需要宣告正規化策略,方法是套用以下註解之一

未設定必要的值

此錯誤表示屬性預期一個值,但未提供任何值。 預設情況下,Gradle 屬性是必要的,也就是說,如果未配置輸入或輸出屬性(透過慣例值或由建置腳本明確配置),則 Gradle 將會失敗,因為它不知道在執行任務時要使用哪個值。

要修正此問題,您必須

  • 明確為此屬性提供一個值(例如,透過在您的建置腳本中配置任務)

  • 或透過使用 @Optional 註解來使屬性成為可選

工件轉換的絕對路徑敏感度的無效使用

此錯誤表示您已將可快取工件轉換的輸入註解為對絕對路徑敏感。 但是,工件轉換在其自己的工作區中隔離執行,例如,該工作區對 clean 建置具有彈性。 即使工件轉換結果無法透過建置快取共享,使用絕對路徑敏感度也沒有意義。

要修正此問題,您必須使用以下其中一種方法變更正規化策略

工件轉換上不應宣告輸出屬性的無效使用

此錯誤表示您已使用輸出註解來註解工件轉換的屬性,這不是為工件轉換註冊輸出的正確方法。

要修正此問題,您必須移除屬性並改用 TransformOutputs 參數。

請參閱 TransformAction#transform(TransformOutputs) 以取得詳細資訊。

欄位上註解的無效使用

此錯誤表示您有一個已註解的欄位,但該欄位沒有 getter。 只有在有對應的 getter 時,Gradle 才會識別欄位上的註解。 如果缺少此 getter,則註解將不起任何作用。

要修正此問題,您需要為此欄位建立一個 getter。 我們也建議註解 getter 而不是欄位。

如果您使用的是 Groovy,則很可能是您不小心將 private 修飾符新增到屬性宣告中

@InputFile
RegularFileProperty inputFile // this is a public property

@InputFile
private RegularFileProperty inputFile // this is a field, remove the `private` modifier

方法上的無效註解

此錯誤表示註解已放置在意外的方法上。 一般來說,@InputFiles@OutputDirectory 之類的註解需要放置在「屬性」方法上。 屬性由具有 getter 定義。

這會導致 Gradle 忽略註解,因此它們通常不用於最新檢查或快取。

要修正此問題,您必須移除註解,為您要使用的屬性建立一個 getter,然後註解 getter。

屬性或欄位上的無效註解

此錯誤表示用於非屬性方法的註解已意外放置在欄位或屬性方法上。 只有輸入和輸出註解(例如 @InputFiles@OutputDirectory)應放置在欄位或「屬性」方法上。 屬性由具有 getter 定義。

這會導致 Gradle 忽略註解,因此當 Gradle 檢查類別中是否有重要註解時,它們通常無法被識別。

要修正此問題,您必須移除註解,或變更方法以符合註解的要求。

帶有 setter 的可變類型

此錯誤表示「可變」類型的屬性也提供 setter。 Gradle 中的可變類型包括 PropertyConfigurableFileCollection

例如,您寫了

class MyTask extends DefaultTask {
    private Property<Integer> x

    @Input
    Property<Integer> getX() { this.x }

    void setX(Property<Integer> x) { this.x = x }
}

但是,Property 等可變類型旨在追蹤相依性以及它們所提供的值的來源。 因此,使其可覆寫是一個錯誤,因為 Gradle 將無法判斷屬性值來自何處。

要修正此問題,您應該將您的屬性設為 final 並移除 setter

class MyTask extends DefaultTask {
    @Input
    final Property<Integer> getX() = ...

您也可以依靠 Gradle 的內建功能來注入 final 屬性

abstract class MyTask {
    abstract Property<Integer> getX()
}

然後需要透過 mutation 方法配置屬性的值

myTask {
    x.set(123)
}

多餘的 getter

此錯誤表示 boolean 屬性同時具有 getis getter 方法。 這是一個問題,因為兩個 getter 可以註解不同,並且 Gradle 無法知道要使用哪一個。

此問題的解決方案是擺脫其中一個 getter 或使用 @Internal 標記其中一個 getter

私有 getter 上的註解

此錯誤表示您已使用輸入或輸出註解來註解私有 getter。 Gradle 不會將私有 getter 視為最新檢查的輸入,這表示您的註解實際上被忽略了。 修正它很重要,因為您可能會認為您已宣告一個輸入,但實際上並非如此。

要修正此問題,請將 getter 設為 public,或註解現有的 getter,或建立新的已註解的 getter。

私有方法上的註解

此錯誤表示您已使用 Gradle 期望查詢的註解來註解私有方法。 Gradle 將無法呼叫私有方法,這表示您的註解實際上被忽略了。 修正它很重要,因為您可能會認為您已宣告一個無法使用的已註解方法。

要修正此問題,請將方法設為 public,或註解另一個新的或現有的 public 方法。

忽略屬性上的註解

此錯誤表示您有一個屬性,該屬性已使用告訴 Gradle 忽略它的註解(例如 @ReplacedBy)註解,但也使用輸入註解(例如 @InputFile)註解。

這是一個錯誤,因為 Gradle 無法判斷屬性是否實際上應該用於最新檢查,也就是說它是否實際上是一個輸入。

要修正此問題,您必須

  • 從屬性中移除輸入註解,或

  • 從屬性中移除忽略註解。

衝突的註解

此錯誤表示屬性已使用衝突的註解註解,也就是說,註解具有不同的、不可調和的語意。

例如,屬性不能同時使用 @InputFile@OutputFile 註解。

要修正此問題,您需要理解不同註解的語意,並僅選擇一個。

註解在特定上下文中無效

此錯誤表示屬性已使用在特定上下文中無效的註解註解。 例如,通常可以使用 @OutputDirectory 註解 DirectoryProperty,但在工件轉換的上下文中,這是無效的,因為工件轉換提供它們自己的工作區。

要修正此問題,您必須移除屬性。

沒有註解的屬性

此錯誤表示屬性未使用輸入或輸出註解註解。 因此,Gradle 不知道此屬性是表示輸入、輸出,還是僅應被忽略。 因此,最新檢查和快取將無法運作。

要修正此問題,您需要使用適當的註解來註解屬性,例如,對於表示輸入目錄的屬性使用 @InputDirectory,或對於表示輸出目錄的屬性使用 @OutputDirectory

或者,如果屬性是內部的,也就是說它不應參與最新檢查(它不是輸入或輸出),那麼您需要使用 @Internal 註解它。

註解與屬性類型不相容

此錯誤表示對於特定類型的屬性,修飾符註解沒有意義。 例如,如果 @SkipWhenEmpty 用於輸出屬性,則會發生這種情況。 因為此組合沒有相關聯的語意,所以 Gradle 無法推斷您的意圖。

要修正此問題,您很可能需要移除衝突的修飾符註解,或檢查實際的屬性類型是否是您想要的類型。

@Input 註解的不正確使用

此錯誤表示屬性已使用 @Input 註解,但應改用 @InputFile@InputDirectory 註解。

如果您在基於檔案的屬性上使用 @Input 註解,Gradle 將不會像您預期的那樣將檔案內容或目錄內容視為輸入。

要修正此問題,您需要告訴 Gradle 檔案屬性是否表示輸入檔案,在這種情況下,您應該使用 @InputFile 註解它,或者表示目錄,在這種情況下,應該使用 @InputDirectory 註解它。 如果您真正想要表達的是實際檔案路徑是一個輸入,那麼您應該傳回一個 String,它對應於檔案的絕對路徑。

@ServiceReference 註解的屬性不是 BuildService

此錯誤表示以 @ServiceReference 註解的屬性的類型未實作 BuildService 介面。

@ServiceReference 註解的屬性旨在保存對 共享建置服務的參考。

任務之間的隱含相依性

此錯誤表示您有一個任務相依於另一個任務,但在這兩個任務之間未宣告任何明確或隱含的相依性。 因此,建置結果取決於任務的執行順序,通常稱為「任務之間的意外相依性」。 通常,這是因為您直接參考另一個任務的輸出檔案,而不是直接將任務用作輸入。

例如,假設您有一個任務,它將 ConfigurableFileCollection 作為輸入,並且您已使用以下方式宣告對 jar 任務的相依性

someTask {
    inputFile.from(jar.archivePath)
}

jar.archivePath 屬性的類型為 File,它不攜帶任何任務相依性。 這表示如果您在呼叫 jar 之後 呼叫 someTask,則任務將成功,但如果移除 jar(例如),則任務將失敗。

要修正此問題,您可以宣告 Property 作為輸入

someTask {
    inputFile.from(jar.archiveFile)
}

jar.archiveFile 屬性的類型為 Provider<RegularFile>,它正確地攜帶任務相依性:Gradle 將能夠知道檔案是由 jar 任務產生的。

實際上,更簡單的方法是將隱含相依性新增到任務本身

someTask {
    inputFile.from(jar)
}

在某些情況下,對於不使用 配置避免 API 的生產者任務,您可以改為宣告任務的明確相依性

someTask {
    dependsOn(producer)
    inputFile.from(producer.someFile)
}

在某些情況下,不希望新增對生產任務的相依性,例如,當消費者為可能的多個任務產生報告時。 在這種情況下,您可以透過使用 Task.mustRunAfter() 在兩個任務之間引入排序

輸入檔案不存在

每當檔案(或目錄)被宣告為任務的輸入,但在執行任務時,檔案(或目錄)不存在時,就會發生此錯誤。

通常,這暗示缺少任務相依性:檔案應在之前執行任務時存在,這表示未執行相依任務。

症狀與任務之間的隱含相依性類似,不同之處在於,在這種情況下,建立檔案的任務尚未執行。

請參閱任務之間的隱含相依性章節以取得可能的解決方案。 如果檔案不是由另一個任務產生的,您可能需要確保檔案在呼叫任務之前存在。 如果您想要宣告的是檔案在執行任務時是否存在並不重要,則可以使用 @InputFiles,它不會因不存在的輸入而失敗

build.gradle.kts
abstract class GreetingFileTask : DefaultTask() {

    @get:InputFiles
    abstract val source: RegularFileProperty

    @get:OutputFile
    abstract val destination: RegularFileProperty

    @TaskAction
    fun greet() {
        val file = destination.get().asFile
        if (source.get().asFile.exists()) {
            file.writeText("Hello ${source.get().asFile.readText()}")
        } else {
            file.writeText("Hello missing file!")
        }
    }
}
build.gradle
abstract class GreetingFileTask extends DefaultTask {

    @InputFiles
    abstract RegularFileProperty getSource()

    @OutputFile
    abstract RegularFileProperty getDestination()

    @TaskAction
    def greet() {
        def file = getDestination().get().asFile
        if (source.get().asFile.exists()) {
            file.write("Hello ${source.get().asFile.text}!")
        } else {
            file.write 'Hello missing file!'
        }
    }
}

意外的輸入檔案或目錄

此錯誤表示屬性預期一個常規檔案作為輸入,但它被提供了一個目錄(或反之亦然)。

例如,如果屬性使用 @InputFile 註解

@InputFile
File getInputFile()

那麼 Gradle 期望輸入檔案是一個常規檔案。 如果輸入是一個目錄,則驗證失敗。

要修正此問題,您有兩個選項

  • 或者您犯了一個錯誤,並提供了目錄而不是檔案,在這種情況下,您只需要修正輸入

  • 或者任務實際上應該使用目錄作為輸入,在這種情況下,您需要將屬性的類型變更為 @InputDirectory

無法寫入輸出檔案或目錄

此錯誤表示

  • 輸出目錄無法寫入,因為已配置的目錄屬性實際上指的是常規檔案(或其他非實際目錄的東西)。

  • 或者,輸出檔案無法寫入,因為已配置的檔案屬性實際上指的是目錄。

  • 或者,輸出位置的父項存在且是一個檔案。

例如,您已將輸出目錄設定為 /some/path/file.txt 而不是 /some/path。 也可能是您已配置類似 /some/path 的輸出目錄,但祖先 /some 是一個常規檔案。

要修正此問題,請確保配置的輸出是一個目錄(對於預期目錄的屬性)或一個檔案(對於預期檔案的任務)。

無法寫入保留位置

此錯誤表示您正嘗試將檔案寫入 Gradle 專門管理的位置。 通常,每當您嘗試將檔案直接寫入工件轉換輸出目錄時,就會發生這種情況。 如果您是故意這樣做的,這是一個錯誤,因為永遠不應直接寫入這些目錄:所有工件轉換寫入都應在工件轉換程式碼本身內執行。

如果您不打算在此目錄中寫入,您應該只需設定您的任務以寫入不同的位置。

檔案輸入中不支援的標記法

此錯誤表示檔案、目錄、檔案集合或巢狀檔案集合屬性指的是 Gradle 無法轉換為檔案的元素。

要修正此問題,請查看錯誤訊息,該訊息指示支援的檔案標記法列表,並確保選擇其中之一。

在原始類型上無效使用 @Optional 註解

此錯誤表示原始類型的屬性也使用 @Optional 註解。 這類似於 Java 中 null 無法指派給原始類型。

要修正此問題,您有兩個選項

  • 移除 @Optional 註解

  • 或者,如果您打算使屬性可為 null,請使用 boxed 類型(例如 Integer 而不是 int)

無法使用具有未知實作的輸入

此錯誤表示任務使用類別作為輸入,並且 Gradle 無法追蹤類別的實作。 Gradle 將以下類別的實作視為任務的輸入

  • 任務類別,

  • 任務動作的類別,

  • 以及任務的巢狀輸入的類別,即使用 @Nested 註解的輸入。

Gradle 無法追蹤類別實作的原因有兩個

  • 非序列化 Java lambda 用於實作類別,

  • 或類別已由 Gradle 未知的類別載入器載入。

使用 Java lambda 表示位元組碼使用 invoke-dynamic 而不是建立實際的子類別。 invoke-dynamic 指令的類別是在 JVM 執行階段產生的,如果目標函數介面不可序列化,則 Gradle 無法跨不同的 JVM 唯一識別此類別。 對於任務動作,這不是問題,因為 Gradle 以特殊方式處理它們。 另一方面,對於由非序列化 lambda 實作的巢狀輸入類別,Gradle 不支援追蹤。 作為一種解決方法,您可以將 lambda 轉換為匿名內部類別,或使目標函數介面可序列化。

對於 Gradle 無法追蹤實作的情況,因為它是由 Gradle 未知的類別載入器載入的,您可以使用 Gradle 的內建方式來載入類別。

缺少不快取的原因

此警告表示任務或工件轉換動作尚未標記為可快取,儘管也沒有理由說明它不可快取。 任務或工件轉換作者應始終提供說明某事物不可快取的原因,方法是使用 @DisableCachingByDefault 註解。

要修正此問題,請使用 @CacheableTask/@CacheableTransform@DisableCachingByDefault(because = "…​") 註解工作類型。

不支援的值類型

此訊息表示任務宣告具有不支援類型的值的輸入屬性。

為了處理此問題,請查看訊息,該訊息指示可能的解決方案列表。

請在下面找到不支援的值類型列表

ResolvedArtifactResult

將 ResolvedArtifactResult 映射為任務輸入

java.net.URL

此類型在以 @Input 註解的屬性上不受支援,因為最新檢查對於此類型可能不一致,從而導致不正確的建置結果。 這是由 Java 中已知問題引起的,其中 java.net.URL 的序列化不正確。 請參閱 OpenJDK 錯誤報告 以取得更多詳細資訊。 為了處理此問題,我們建議改用 java.net.URI

巢狀映射的不支援的鍵類型

此錯誤表示巢狀映射宣告了不支援類型的鍵。 Gradle 使用鍵來產生(子)屬性的名稱。 僅允許類型為 EnumIntegerString 的鍵,這樣可確保這些名稱是唯一且格式正確的,並且比依賴 toString() 產生此類名稱更可取。

要修正此問題,請將鍵的類型變更為 EnumIntegerString

不支援的巢狀類型

此錯誤表示不支援的類型被註解為巢狀。 巢狀類型預期要宣告一些已註解的屬性(這些屬性本身會檢查註解)或一些條件行為,其中將類型本身捕獲為輸入很重要。 Java SE API 的類型、Kotlin stdlib 的類型和 Groovy 的 GString 不受支援,因為它們都不滿足這些要求。

為了修正這個問題,請宣告巢狀型別,例如 Provider<T>Iterable<T><MapProperty<K, V>>,其中 TV 具有一些已註解的屬性,或某些需要將類型作為輸入來擷取的行為。