I’m writing a custom plugin and inside that I want to override the jar task’s manifest based on properties the user configures. It seems my issue has to do with lazy loading - its trying to evaluate my project extension properties eagerly (when the plugin is applied) vs lazily (when the jar task actually needs to execute). Any help on how to fix this?
In my multiproject build I have projects with an existing MANIFEST.MF file, others do not have it. So I do this, overriding the “jar” task:
jar {
manifest {
// benutze das im Projekt vorliegende File, falls vorhanden:
def manif = "${projectDir}/META-INF/MANIFEST.MF"
if (new File(manif).exists()) {
from file(manif)
}
else {
logger.info(project.name + " doesn't have a META-INF/MANIFEST.MF.")
manifest.attributes provider: 'xyz,abc'
manifest.attributes project: project.name
manifest.attributes Build: new Date()
}
}
}
Note that the methods on javadoc:org.gradle.api.java.archives.Manifest that you use to set attribute accept ‘Object’ for the value part. This is a common pattern used in Gradle to achieve laziness; the object will be converted to a ‘String’ at the latest possible moment by calling ‘toString()’ on it.
This means that you can set a value that is a calculation. You can either write your own class for this, or use Groovy’s Lazy GString functionality. See this blog post for some more on this topic.
Using a closure inside of the GString works like a charm. Great feature to know about. Also putting my code inside a project.afterEvaluate block works too, but I like the GString/closure better as I can scope my classes without having to think about “did I put the caller to my class inside an afterEvaluate?” Wherever I need these custom properties as strings I can just use the Closure idea.
I also spoke with Peter Niederwieser and he mentioned using the conventionMapping approach, so in my plugin I could do something like this
‘afterEvaluate’ is to be avoided if possible as it makes it difficult for users to override your plugin’s behaviour if they need to. And convention mappings should be avoided if possible for the time being because they aren’t part of the public API.