【问题标题】:How can I modify Java source code in my Gradle project prior to compilation without modifying the files on disk?如何在编译前修改 Gradle 项目中的 Java 源代码而不修改磁盘上的文件?
【发布时间】:2020-01-11 07:05:42
【问题描述】:

我有一个 Gradle 项目。在我的源代码中,我有一些注释(除其他外)采用相同的字符串。但是,相同的字符串存在于配置文件中,我只想引用该文件,因此我只需在一个地方更改此字符串即可更改它的所有实例。因此,我必须从文件中读取字符串,这意味着该字符串不是编译时常量。因此我不能使用从文件中读取的字符串作为注释参数。

// I have this.
@Annotation("some_string")
Object a;

@Annotation("some_string")
Object b;


// This doesn't work
String ss = // read a file, fetch the string from the file.

@Annotation(ss)
Object a;

@Annotation(ss)
Object b;

我想知道 Gradle 中是否有一种方法可以在编译之前修改源代码,从而允许我使用单个变量控制所有注释参数。

即,在源代码中,我可以使用 @Annotation("%%some_string%%") 并将所有出现的 %%some_string%% 替换为 Gradle 任务中的变量。用类似的东西简单地修改每个源文件就很容易了

def annotation_variable = // read a file, fetch the string from the file.
for ( f in srcFileTree ) {
    def text = file(f).text
    file(f).text = text.replaceAll("%%some_string%%", annotation_variable)
}

但是,这将永久修改源文件。因此,我正在寻找一种方法来修改管道中的文件,而无需实际修改磁盘上的文件。有没有办法做到这一点?

【问题讨论】:

  • 我不能简单地定义一个变量并将该变量用作字符串:是的,你可以。该变量必须是编译时常量(public static final)。但这似乎是你想要的。
  • @JBNizet 啊,好点。我已经编辑了我的问题以解释为什么这在我的情况下不起作用。
  • 当然可以,但我不会那样做。为什么不把变量名而不是它的值放在注解中,并在运行时从资源文件中读取对应的值?
  • @JBNizet 抱歉,我不完全确定您的意思。如果您建议让注释代码从文件中读取值,那么我认为这是一个有效的解决方案,但我的示例过于简单化了。我有多个共享相同问题的第 3 方注释。我将不得不扩展它们中的每一个并编写代码以从配置文件中读取它们中的每一个。虽然不是非常复杂,但它在我的工作流程中的扩展性不如我相信我正在寻找的解决方案那样。
  • 我仍然认为这将是一个更好的解决方案,但无论如何,如果您想坚持使用源预处理器,那么您必须创建一个任务,将您的源复制并过滤到一个目录(让我们在 build 下将其命名为“actualSources”),然后将 gradle SourceSet 配置为从该 actualSources 目录中读取。

标签: java gradle build.gradle


【解决方案1】:

将您的java 模板放在与普通java 源不同的目录中(例如src/template/java)。这将减少 Gradle 所需的“工作”,也意味着您的 IDE 不会尝试编译模板。

然后添加一个任务来替换模板中的标记并将它们复制到$buildDir 下的目录(因此它们通过“清理”被删除并且永远不会提交给 git)

task generateJava(type: Copy) {
   from 'src/template/java'
   into "$buildDir/generated/java"
   filter(ReplaceTokens, tokens: [someToken: 'someReplacement'])
} 

现在将生成的目录添加到“main”java sourceSet 并将任务连接到DAG

sourceSets.main.java.srcDir  "$buildDir/generated/java"
compileJava.dependsOn 'generateJava'

假设您的 IDE 集成了 Gradle,您的 IDE 现在也应该编译生成的源代码

请参阅 working with files 文档中的“在复制文件时过滤文件”

【讨论】:

  • 尽管不是我使用的解决方案,但根据我所阅读的内容以及我在这个问题的 cmets 中与 JB Nizet 的conversation,这似乎是最适合该问题的答案。谢谢。
  • 是的,我回答了您的请求,但不相信这是最好的解决方案。在运行时从类路径中查找属性文件可以解决您的问题。我上面的解决方案有有效的用例,但不是你的
【解决方案2】:

您可以修改输出文件而不是源文件。 War 任务和 replaceTokens 过滤器示例(使用您喜欢的任务和过滤器):

tasks.withType(War) { warTask ->
        ...
        from('src/main/java/YOUR_PACKAGE') {
            include YOUR_FILE(s)

            filter ReplaceTokens, beginToken: '@', endToken: '@', tokens: [
                    'YOUR_TOKEN_NAME': YOUR_VALUE
            ]
        }
    }

【讨论】:

  • @barfuin 不,见here
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-02
  • 1970-01-01
  • 1970-01-01
  • 2014-12-22
  • 1970-01-01
  • 1970-01-01
  • 2016-01-20
相关资源
最近更新 更多