SMUsamaShah
SMUsamaShah

Reputation: 7890

How to set a property of a task lazily?

task task1(type: ProduceFilesTaskType) {
   outDir = file("$projectDir/some/files")
}

task task2(type: ConsumeFilesTaskType) {
   fileList = file("$doSomething.outDir/somefolders/").listFiles().toList() // null pointer exception
}

I don't have the source of ConsumeFilesTaskType and it requires a List<File> fileList which is produced by task1.

Now because these files don't exist in configuration phase, gradle fails at configuration stage with error Cannot invoke method toList() on null object because there are no files.

I can probably do this

task task2(type: ConsumeFilesTaskType) {
   fileList = new ArrayList<File>() // don't fail
   doFirst {
      fileList = file("$doSomething.outDir/somefolders/").listFiles().toList() // actual list of files
   }
}

Is this the standard way or is there a better way to set/evaluate a property lazily?

Upvotes: 0

Views: 269

Answers (1)

Xinchao
Xinchao

Reputation: 3541

There are a lot constructs in Gradle that are lazily evaluated. In a way Gradle is built on top of the idea of lazy evaluation. That being said, it also depends on how your ConsumeFilesTaskType is implemented. Nothing can help if the task itself is not using the fileList parameter lazily.

If the fileList is typed as Iterable<File>, or the Gradle provided type FileCollection, you can assign it to project.fileTree() at configuration phase:

Iterable<File> fileList;

task myTask {
    fileList = project.fileTree("build") // build might not exist at this moment
    
    doLast {
        fileList.forEach { println it.name }
    }
}

There is a similar method project.files() that creates a ConfigurableFileCollection object. The project.files() documentation does a better job at explaining what it means by "lazy" and "live". project.fileTree() returns a ConfigurableFileTree that is also lazy and live. The difference is that ConfigurableFileTree interprets the files added as roots. When iterating, ConfigurableFileTree recursively traverses these root directories to collect actual files for the caller.

Upvotes: 1

Related Questions