如何在编译之前修改Gradle项目中的Java源代码而不修改磁盘上的文件?

如何在编译之前修改Gradle项目中的Java源代码而不修改磁盘上的文件?,java,gradle,build.gradle,Java,Gradle,Build.gradle,我有一个Gradle项目。在我的源代码中,我有一些注释(除其他外)采用相同的字符串。但是,配置文件中存在相同的字符串,我只想引用该文件,因此我只需在一个位置更改该字符串,即可更改其所有实例。因此,我必须从文件中读取字符串,这意味着该字符串不是编译时常量。因此,我不能将从文件中读取的字符串用作注释参数 // I have this. @Annotation("some_string") Object a; @Annotation("some_string") Object b; // Thi

我有一个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中是否有一种方法可以在编译之前修改源代码,使我能够用一个变量控制所有注释参数

也就是说,在源代码中,我可以使用
@注释(“%%some_string%%”)
并用Gradle任务中的变量替换所有出现的
%%some_string%%
。只需使用以下内容修改每个源文件就足够简单了

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)
}

但是,这将永久修改源文件。因此,我正在寻找一种方法来修改管道中的文件,而不实际修改磁盘上的文件。是否仍要执行此操作?

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


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

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

现在将生成的目录添加到“main”java源集中,并将任务连接到

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


请参阅文档中的“复制时过滤文件”

我不能简单地定义变量并将该变量用作字符串:是的,您可以。该变量必须是编译时常量(publicstaticfinal)。但这似乎正是你想要的。@JBNizet啊,说得好。我编辑了我的问题来解释为什么这在我的情况下不起作用。当然有可能,但我不会那样做。为什么不把变量名而不是它的值放在注释中,并在运行时从资源文件中读取相应的值?@jbnize对不起,我不完全清楚你的意思。如果您建议让注释代码从文件中读取值,那么我认为这是一个有效的解决方案,但我的示例过于简单。我有多个第三方注释共享同一问题。我必须扩展它们中的每一个,并编写代码从每个配置文件中读取它们。虽然不太复杂,但它在我的工作流程中的可扩展性不如我所寻找的解决方案。我仍然认为这是一个更好的解决方案,但无论如何,如果你想坚持使用源预处理器,那么你必须创建一个任务,将你的源复制并过滤到一个目录(让我们称之为“actualSources”)在build下,然后将gradle SourceSet配置为从该actualSources目录中读取。尽管不是我所使用的解决方案,但根据我所阅读的内容以及我在这个问题的评论中对JB Nizet的看法,这似乎是最适合这个问题的答案。谢谢。是的,我回答了你的要求,但不认为这是最好的解决方案。在运行时从类路径查找属性文件可以解决您的问题。上面我的解决方案有一些有效的用例,只是没有yours@barfuin不,看
tasks.withType(War) { warTask ->
        ...
        from('src/main/java/YOUR_PACKAGE') {
            include YOUR_FILE(s)

            filter ReplaceTokens, beginToken: '@', endToken: '@', tokens: [
                    'YOUR_TOKEN_NAME': YOUR_VALUE
            ]
        }
    }
task generateJava(type: Copy) {
   from 'src/template/java'
   into "$buildDir/generated/java"
   filter(ReplaceTokens, tokens: [someToken: 'someReplacement'])
} 
sourceSets.main.java.srcDir  "$buildDir/generated/java"
compileJava.dependsOn 'generateJava'