I want to replace few lines in my Config.java file before the code gets compiled. All I was able to find is to parse file through filter during copying it. As soon as I have to copy it I had to save it somewhere - thats why I went for solution: copy to temp location while replacing lines > delete original file > copy duplicated file back to original place > delete temp file. Is there better solution?
4 Answers
May be you should try something like ant's replaceregexp:
task myCopy << {
ant.replaceregexp(match:'aaa', replace:'bbb', flags:'g', byline:true) {
fileset(dir: 'src/main/java/android/app/cfg', includes: 'TestingConfigCopy.java')
}
}
This task will replace all occurances of aaa
with bbb
. Anyway, it's just an example, you can modify it under your purposes or try some similar solution with ant.

- 27,441
- 9
- 87
- 82
-
3See another aproach at: [http://stackoverflow.com/a/17572644/890357](http://stackoverflow.com/a/17572644/890357) – marciowb May 17 '16 at 23:36
To complement lance-java
's answer, I found this idiom more simple if there's only one value you are looking to change:
task generateSources(type: Copy) {
from 'src/replaceme/java'
into "$buildDir/generated-src"
filter { line -> line.replaceAll('xxx', 'aaa') }
}
Caveat: Keep in mind that the Copy
task will only run if the source files change. If you want your replacement to happen based on other conditions, you need to use Gradle's incremental build features to specify that.

- 9,888
- 6
- 55
- 76
-
1Careful, we got BURNED huge. we run with -Pversion={version} BUT that target keeps saying source files are not dirty so our newer versions never were put into the file. It works for many things but not versioning. we found out the hard way there. – Dean Hiller Apr 14 '20 at 23:09
-
@DeanHiller thanks for your comment. I am not 100% sure I understand what you mean. Are you saying that you had source files that had not changed, and thus Gradle was not "changing" them the way you wanted, even though it should have changed the "version" inside them? – Vic Seedoubleyew Apr 15 '20 at 09:04
-
we tried to use that method to version, but if the source file didn't change, it actually would not run at all and would do 0 replacement, so we would end up with 'version-token-to-be-replaced' in our output files when switching from a dev build to a release build. Not sure the best way to do that yet tbh....perhaps just file gen. – Dean Hiller Apr 18 '20 at 14:17
-
I get it. Indeed the Copy task runs only if the source files changed. That is its default behavior. In your case you should think about what is the trigger that should cause this replacement to happen. Do you want it to run every time Gradle is run? Is there another condition? Once you figure this out you should use Gradle's incremental build features to specify it: for example specifying the task's inputs, outputs or updateToDateWhen. – Vic Seedoubleyew Apr 20 '20 at 09:30
-
I'll add this caveat to my answer. Feel free to post the same comment on other answers, they are all concerned by this corner case – Vic Seedoubleyew Apr 20 '20 at 09:30
-
I can tell you `filter` is evil. It causes `java.lang.ClassFormatError: Incompatible magic value 4022320623 in class file...` for me. – Alexis Evelyn Oct 25 '20 at 20:55
-
@AlexisEvelyn I would be very surprised that this would be linked to the use of `filter`. I don't see any connection. – Vic Seedoubleyew Oct 27 '20 at 08:31
- I definitely wouldn't overwrite the original file
- I like to keep things directory based rather than filename based so if it were me, I'd put Config.java in it's own folder (eg
src/replaceme/java
) - I'd create a
generated-src
directory under$buildDir
so it's deleted via theclean
task.
You can use the Copy task and ReplaceTokens filter. Eg:
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

- 25,497
- 4
- 59
- 101
-
I already used the replace method and its working flawlessly but once I edit Config.java file manually I could reach some unwanted states, so your solution seems much better. What does exactly compileJava.source = [files] do? How does it know if I want to replace Config.java in lets say package 'com.example.cfg' and not file with same name in package 'com.example.remote.cfg'? – Srneczek Nov 05 '15 at 21:13
-
As I said, I prefer using directories rather than specific filename patterns. So in my example everything in `src/replaceme/java` will be replaced regardless of package. `compileJava.source generateSources.outputs.files` invokes [JavaCompile.source(...)](https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/compile/JavaCompile.html) which ultimately adds the generated sources so that they compiled alongside the normal source files (in `src/main/java`). There is no "=" sign in my suggestion – lance-java Nov 06 '15 at 10:40
If you do wish to overwrite the original file, using a temp file strategy, the following will create the filtered files, copy them over the original, and then delete the temp files.
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)

- 1,544
- 1
- 16
- 27