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

如何在Gradle的Jar任务中排除指定类?自定义插件场景

解决Gradle插件中用自定义类替换默认编译类的问题

问题分析

你遇到的核心问题:

  • 直接修改sourceSet输出目录破坏构建链(依赖该sourceSet的后续任务会出现异常)
  • Jar任务的exclude规则未生效,且触发重复类报错,根源在于:
    1. 默认Jar任务已自动包含sourceSets.main.output,额外添加会导致输入重复
    2. 单个CopySpec的DuplicatesStrategy设置不生效,需在Jar任务全局级别配置
    3. 排除逻辑中的路径转换错误,导致无法匹配到需要跳过的类文件

解决方案

正确思路:控制Jar任务的输入来源,先加入自定义类目录,再加入默认sourceSet输出但排除被自定义类覆盖的文件,同时在Jar任务级别设置重复策略兜底,完全保留原有构建链。

Kotlin DSL 插件实现示例

class CustomPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        val sourceSets = project.extensions.getByType(SourceSetContainer::class.java)
        val mainSourceSet = sourceSets.named("main").get()
        val customClassesDir = project.layout.buildDirectory.dir("weaved-classes/java/main")

        project.tasks.named<Jar>("jar") {
            // 先添加自定义类目录,优先级高于默认类
            from(customClassesDir) {
                include("**/*.class")
            }
            // 添加默认sourceSet输出,排除已被自定义类覆盖的文件
            from(mainSourceSet.output) {
                val customClassPaths = customClassesDir.get().asFile.walkTopDown()
                    .filter { it.isFile && it.extension == "class" }
                    .map {
                        // 转换为Jar包内的相对路径(统一用/分隔)
                        customClassesDir.get().asFile.toURI().relativize(it.toURI()).path
                    }
                    .toSet()
                exclude { details ->
                    customClassPaths.contains(details.relativePath.pathString)
                }
            }
            // 全局设置重复策略,兜底防止遗漏
            duplicatesStrategy = DuplicatesStrategy.EXCLUDE
        }
    }
}

Java 插件实现示例

public class CustomPlugin implements Plugin<Project> {
    @Override
    public void apply(Project project) {
        SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
        SourceSet mainSourceSet = sourceSets.named("main").get();
        Provider<Directory> customClassesDir = project.getLayout().getBuildDirectory().dir("weaved-classes/java/main");

        project.getTasks().named("jar", Jar.class, jar -> {
            // 加入自定义类目录
            jar.from(customClassesDir, spec -> {
                spec.include("**/*.class");
            });

            // 加入默认编译输出并排除重复类
            jar.from(mainSourceSet.getOutput(), spec -> {
                // 预生成自定义类在Jar中的相对路径集合
                Set<String> customClassPaths = customClassesDir.get().getAsFile().toPath()
                        .walk(10) // 递归深度按需调整
                        .filter(Files::isRegularFile)
                        .filter(path -> path.getFileName().toString().endsWith(".class"))
                        .map(path -> {
                            Path relative = customClassesDir.get().getAsFile().toPath().relativize(path);
                            return relative.toString().replace(File.separatorChar, '/');
                        })
                        .collect(Collectors.toSet());

                spec.exclude(details -> {
                    String archivePath = details.getRelativePath().getPathString();
                    return customClassPaths.contains(archivePath);
                });
            });

            // Jar任务级别设置重复策略,覆盖全局
            jar.setDuplicatesStrategy(DuplicatesStrategy.EXCLUDE);
        });
    }
}

关键要点说明

  1. 输入顺序:先添加自定义类目录,配合DuplicatesStrategy.EXCLUDE确保自定义类覆盖默认类
  2. 路径匹配:统一使用/作为路径分隔符,保证和Jar包内的相对路径完全匹配
  3. 重复策略:必须在Jar任务全局设置duplicatesStrategy,单个CopySpec的设置无法作用于整个任务
  4. 构建链保护:不修改sourceSet的默认输出目录,仅在Jar打包阶段控制内容,完全兼容原有构建流程

为什么之前的代码失败?

  • Kotlin代码中,exclude("*")仅对当前from块生效,无法覆盖Jar任务默认包含的sourceSet输出
  • Java代码中,路径转换逻辑错误(用本地文件路径而非Jar内相对路径),导致排除规则无法匹配目标文件
  • DuplicatesStrategy设置在单个CopySpec中,未作用于整个Jar任务,因此仍会触发重复类报错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 12:03:21