Gradle 任务替换 .java 文件中的字符串

Gradle task replace string in .java file

我想在编译代码之前替换 Config.java 文件中的几行。我所能找到的只是在复制过程中通过过滤器解析文件。一旦我必须复制它,我就必须将它保存在某个地方——这就是我寻求解决方案的原因:在替换行时复制到临时位置 > 删除原始文件 > 将复制的文件复制回原始位置 > 删除临时文件。有更好的解决方案吗?

也许你应该尝试像 ant 那样的东西 replaceregexp:

task myCopy << {
    ant.replaceregexp(match:'aaa', replace:'bbb', flags:'g', byline:true) {
        fileset(dir: 'src/main/java/android/app/cfg', includes: 'TestingConfigCopy.java')
    }
}

此任务会将出现的所有 aaa 替换为 bbb。无论如何,这只是一个例子,你可以根据你的目的修改它或者用ant尝试一些类似的解决方案。

  1. 我绝对不会覆盖原文件
  2. 我喜欢基于目录而不是基于文件名,所以如果是我,我会把 Config.java 放在它自己的文件夹中(例如 src/replaceme/java
  3. 我会在 $buildDir 下创建一个 generated-src 目录,以便通过 clean 任务将其删除。

您可以使用复制任务和 ReplaceTokens 过滤器。例如:

apply plugin: 'java'
task generateSources(type: Copy) {
    from 'src/replaceme/java'
    into "$buildDir/generated-src"
    filter(ReplaceTokens, tokens: [
        'xxx': 'aaa', 
        'yyy': 'bbb'
    ])
}
// the following lines are important to wire the task in with the compileJava task
compileJava.source "$buildDir/generated-src"
compileJava.dependsOn generateSources

为了补充 lance-java 的回答,我发现如果您只想更改一个值,这个习惯用法会更简单:

task generateSources(type: Copy) {
    from 'src/replaceme/java'
    into "$buildDir/generated-src"
    filter { line -> line.replaceAll('xxx', 'aaa') }
}

警告:请记住,如果源文件发生更改,Copy 任务只会 运行。如果您希望根据其他条件进行替换,则需要使用 Gradle 的增量构建功能来指定。

如果您确实希望覆盖原始文件,使用临时文件策略,以下将创建过滤后的文件,将它们复制到原始文件上,然后删除临时文件。

task copyAtoB(dependsOn: [existingTask]) {
    doLast {
        copy {
            from("folder/a") {
                include "*.java"
            }
            // Have to use a new path for modified files
            into("folder/b")
            filter {
                String line ->
                    line.replaceAll("changeme", "to this")
            }
        }
    }
}

task overwriteFilesInAfromB(dependsOn: [copyAtoB]) {
    doLast {
        copy {
            from("folder/b") {
                include "*.java"
            }
            into("folder/a")
        }
    }
}

// Finally, delete the files in folder B
task deleteB(type: Delete, dependsOn: overwriteFilesInAfromB) {
    delete("folder/b")
}

nextTask.dependsOn(deleteB)