You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

根项目自定义约定插件为何覆盖子项目插件的传递依赖?

问题:Gradle约定插件导致Jackson版本冲突

构建环境设置

项目结构如下:

.
├── gradle
│   ├── build-logic
│   │   ├── buf-convention
│   │   │   ├── build.gradle.kts
│   │   │   └── src
│   │   │       └── main
│   │   │           └── kotlin
│   │   │               └── buf-check-convention.gradle.kts
│   │   ├── jib-convention
│   │   │   ├── build.gradle.kts
│   │   │   └── src
│   │   │       └── main
│   │   │           └── kotlin
│   │   │               └── jib-configuration-convention.gradle.kts
│   │   └── settings.gradle.kts
├── subproject-with-buf
│   ├── build.gradle.kts
│   └── src
│       └── main
│           └── proto
│               └── com
│                   └── example
│                       └── constants.proto
├── build.gradle.kts
└── settings.gradle.kts

build-logic包含两个Gradle约定插件:

  • 适配Google Jib Gradle插件的约定
  • 适配Buf Gradle插件的约定

Jib插件约定配置

// gradle/build-logic/jib-convention/build.gradle.kts
plugins {
    `kotlin-dsl`
}

repositories {
    gradlePluginPortal()
}

dependencies {
    implementation("com.google.cloud.tools:jib-gradle-plugin:3.4.3")
}

// gradle/build-logic/jib-convention/src/main/kotlin/jib-configuration-convention.gradle.kts
plugins {
    id("com.google.cloud.tools.jib")
}

jib {
    from {
        image = "gcr.io/distroless/java21-debian12:debug"
    }
}

Buf插件约定配置

// gradle/build-logic/buf-convention/build.gradle.kts
plugins {
    `kotlin-dsl`
}

repositories {
    gradlePluginPortal()
}

dependencies {
    implementation("com.google.protobuf:protobuf-gradle-plugin:0.9.4")
    implementation("build.buf:buf-gradle-plugin:0.10.0")
}

// gradle/build-logic/buf-convention/src/main/kotlin/buf-check-convention.gradle.kts
plugins {
    id("java")
    id("com.google.protobuf")
    id("build.buf")
    id("maven-publish")
}

buf {
    publishSchema = true
    previousVersion = "0.0.1-SNAPSHOT"

    imageArtifact {
        groupId = "com.buf.image"
        artifactId = "app"
        version = "0.0.1-SNAPSHOT"
    }
}

val repoUri = uri("file://${rootProject.projectDir}/gradle/buf-repo")

repositories {
    mavenCentral()
    maven {
        url = repoUri
    }
}

publishing {
    repositories {
        maven {
            url = repoUri
            name = "LocalArtifacts"
        }
    }
}

重要说明:Jib Gradle插件v3.4.3依赖Jackson v2.15.2,而Buf Gradle插件v0.10.0要求类路径中使用Jackson v2.17.2。

根项目settings.gradle.kts配置:

rootProject.name = "gradle-overrides-jackson-with-lower-version"

include("subproject-with-buf")

pluginManagement {
    includeBuild("gradle/build-logic")
}

问题描述

根项目应用jib-configuration-convention,子项目subproject-with-buf应用buf-check-convention时,执行./gradlew :subproject-with-buf:writeWorkspaceYaml抛出java.lang.NoSuchMethodError,错误栈如下:

java.lang.NoSuchMethodError: 'void com.fasterxml.jackson.core.base.GeneratorBase.<init>(int, com.fasterxml.jackson.core.ObjectCodec, com.fasterxml.jackson.core.io.IOContext)'
        at com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.<init>(YAMLGenerator.java:299)
        at com.fasterxml.jackson.dataformat.yaml.YAMLFactory._createGenerator(YAMLFactory.java:532)
        at com.fasterxml.jackson.dataformat.yaml.YAMLFactory.createGenerator(YAMLFactory.java:481)
        at com.fasterxml.jackson.dataformat.yaml.YAMLFactory.createGenerator(YAMLFactory.java:15)
        at com.fasterxml.jackson.databind.ObjectMapper.createGenerator(ObjectMapper.java:1215)
        at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3964)
        at build.buf.gradle.BufYamlGenerator.generate(BufYamlGenerator.kt:43)

插件应用方式:

// 根项目build.gradle.kts
plugins {
    id("java")
    id("jib-configuration-convention")
}

// subproject-with-buf/build.gradle.kts
plugins {
    id("buf-check-convention")
}

sourceSets {
    main {
        proto {
            srcDirs("src/main/proto")
        }
    }
}

测试用proto文件:

// subproject-with-buf/src/main/proto/com/example/constants.proto
syntax = "proto3";

package com.example;

enum Boolean {
  FALSE = 0;
  TRUE = 1;
}

复现步骤

  • 按上述结构创建项目
  • 将Buf插件版本改为v0.9.1,执行./gradlew :subproject-with-buf:publishBufImagePublicationPublicationToLocalArtifactsRepository填充本地Maven仓库
  • 切换回Buf插件v0.10.0,执行./gradlew :subproject-with-buf:writeWorkspaceYaml --stacktrace即可触发错误

调试尝试

  • 自定义任务查看类路径,显示子项目buildscript类路径中的Jackson为v2.17.2,符合预期:
allprojects {
    tasks.register("printClasspath") {
        doLast {
            buildscript.configurations
                .named("classpath").get()
                .asFileTree
                .filter { it.name.contains("jackson")}
                .forEach { println(it) }
        }
    }
}
  • 直接在项目中应用Jib插件而非通过约定插件时,问题消失

原因分析

Gradle的构建脚本类路径采用父项目优先的加载机制:

  1. 根项目应用jib-configuration-convention时,约定插件依赖的Jib插件会将Jackson v2.15.2引入根项目的buildscript类路径
  2. 子项目的buildscript类路径继承自根项目,类加载器会优先加载根项目类路径中的低版本Jackson
  3. 虽然Buf约定插件依赖高版本Jackson,但类加载时已经加载了低版本,导致Buf插件调用不存在的方法

直接应用Jib插件时,Gradle会在同一个项目的buildscript依赖解析中自动处理版本冲突,选择更高版本的Jackson;但通过约定插件时,根项目先加载低版本,子项目无法覆盖。

解决方法

方法1:规范约定插件的依赖声明(推荐)

在jib-convention的build.gradle.kts中,将implementation改为compileOnly依赖Jib插件:

// gradle/build-logic/jib-convention/build.gradle.kts
dependencies {
    compileOnly("com.google.cloud.tools:jib-gradle-plugin:3.4.3")
}

这样约定插件只会引入Jib插件的API,不会将其传递依赖(如Jackson)打包到约定插件的类路径中。当项目应用约定插件时,Gradle会自动解析Jib插件的依赖,并通过自身的版本冲突解决机制选择合适的Jackson版本。

方法2:强制统一Jackson版本

在根项目的build.gradle.kts中添加buildscript依赖约束,强制所有Jackson依赖使用v2.17.2:

buildscript {
    dependencies {
        constraints {
            implementation("com.fasterxml.jackson.core:jackson-core:2.17.2")
            implementation("com.fasterxml.jackson.core:jackson-databind:2.17.2")
            implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.17.2")
        }
    }
}

此方法直接强制替换所有Jackson版本,确保Buf插件能使用兼容的版本,但需要同步维护版本号。

方法3:避免全局应用Jib约定插件

如果只有部分子项目需要Jib插件,仅在这些子项目中应用jib-configuration-convention,不要在根项目全局应用,这样根项目的buildscript类路径不会引入低版本Jackson,子项目的Buf插件可正常使用高版本依赖。


内容的提问来源于stack exchange,提问作者Kirill

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 09:44:52