You probably know about using Annotation Types for your custom Gradle plugin input values:
class MyTask extends DefaultTask {
@Input
String aSimpleProperty
@InputFile
File anInputFile
@Input
@Optional
String[] optionalProperty
@OutputFile
File anOutputFile
@TaskAction
def performTask() {
// …
}
}
Using complex task input
When using a more complex input model, you can try something like this:
class TaskConfiguration {
String aSimpleProperty
File anInputFile
String[] optionalProperty
}
class MyTask extends DefaultTask {
@Input
TaskConfiguration myConfiguration
@OutputFile
File anOutputFile
@TaskAction
def performTask() {
// …
}
}
After running that task Gradle will try to serialize your TaskConfiguration, but will fail due to the missing Serializable interface declaration. Gradle needs to serialize your input so that it can detemine in following builds whether any input has changed. You get error messages like:
org.gradle.api.UncheckedIOException: Could not add entry ‚:projectname:taskname‘ to cache taskArtifacts.bin (/home/user/projectname/.gradle/1.8/taskArtifacts/taskArtifacts.bin).
at org.gradle.cache.internal.btree.BTreePersistentIndexedCache.put(BTreePersistentIndexedCache.java:156)
at org.gradle.cache.internal.MultiProcessSafePersistentIndexedCache$2.run(MultiProcessSafePersistentIndexedCache.java:53)
Caused by: java.io.NotSerializableException: de.projectname.TaskConfiguration
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180)
Making the task input serializable…
Adding the java.io.Serializable interface to your TaskConfiguration won’t be enough, because Gradle also needs an equals() implementation to compare the serialized model with the current one. That’s quite much compared to the properties in your configuration model. Especially when using the daemon you can get error messages like:
org.gradle.api.UncheckedIOException: Could not read entry ‚:projectname:taskname‘ from cache taskArtifacts.bin (/home/user/projectname/.gradle/1.8/taskArtifacts/taskArtifacts.bin).
at org.gradle.cache.internal.btree.BTreePersistentIndexedCache.get(BTreePersistentIndexedCache.java:129)
Caused by: java.lang.ClassNotFoundException: de.projectname.TaskConfiguration
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
… the Gradle way
Looking at the Gradle documentation you’ll step over the @Nested annotation. The @Nested annotation allows you to configure each property of your task input like this:
class TaskConfiguration {
@Input
String aSimpleProperty
@InputFile
File anInputFile
@Input
@Optional
String[] optionalProperty
}
class MyTask extends DefaultTask {
@Nested
TaskConfiguration myConfiguration
@OutputFile
File anOutputFile
@TaskAction
def performTask() {
// …
}
}
You might as well use @Nested to create a more complex model:
class NestedConfiguration {
@Input
String yetAnotherProperty
}
class TaskConfiguration {
@Input
String aSimpleProperty
@InputFile
File anInputFile
@Input
@Optional
String[] optionalProperty
@Nested
NestedConfiguration nestedConfig
}
class MyTask extends DefaultTask {
@Nested
TaskConfiguration myConfiguration
@OutputFile
File anOutputFile
@TaskAction
def performTask() {
// …
}
}
That way you don’t need any Serializable or equals() boilerplate code and Gradle can still check your task configuration for changes. You can find an example at the gradle-debian-plugin repository.