task task1(type: ProduceFilesTaskType) {
outDir = file("$projectDir/some/files")
}
task task2(type: ConsumeFilesTaskType) {
fileList = file("$doSomething.outDir/somefolders/").listFiles().toList() // null pointer exception
}
У меня нет источника ConsumeFilesTaskType
, и для этого требуется List<File> fileList
, созданный task1
.
Теперь, поскольку эти файлы не существуют на этапе настройки, gradle завершается сбоем на этапе настройки с ошибкой Cannot invoke method toList() on null object
из-за отсутствия файлов.
Я, наверное, могу это сделать
task task2(type: ConsumeFilesTaskType) {
fileList = new ArrayList<File>() // don't fail
doFirst {
fileList = file("$doSomething.outDir/somefolders/").listFiles().toList() // actual list of files
}
}
Это стандартный способ или есть лучший способ лениво установить/оценить свойство?
@daggett вместе с инициализацией свойства с пустым экземпляром?
Исключение нулевого указателя возникает не потому, что fileList имеет значение null, а file("$doSomething.outDir/somefolders/") возвращает значение null. Я не думаю, что вам нужен fileList = new ArrayList<File>(), если не происходит что-то еще
В Gradle есть множество конструкций, которые оцениваются лениво. В некотором смысле Gradle построен на основе идеи ленивых вычислений. При этом это также зависит от того, как реализован ваш ConsumeFilesTaskType. Ничего не поможет, если сама задача не лениво использует параметр fileList.
Если fileList имеет тип Iterable<File>
или предоставленный Gradle тип FileCollection
, вы можете назначить его для project.fileTree() на этапе настройки:
Iterable<File> fileList;
task myTask {
fileList = project.fileTree("build") // build might not exist at this moment
doLast {
fileList.forEach { println it.name }
}
}
Существует аналогичный метод project.files()
, который создает объект ConfigurableFileCollection. Документация project.files()
лучше объясняет, что значит «ленивый» и «живой». project.fileTree()
возвращает ConfigurableFileTree, который также является ленивым и живым. Разница в том, что ConfigurableFileTree интерпретирует добавленные файлы как корневые. При повторении ConfigurableFileTree рекурсивно обходит эти корневые каталоги, чтобы собрать фактические файлы для вызывающего объекта.
doFirst, doLast — стандартный способ