skip to content

What are the lazy .elements and .asFileTree views of a ConfigurableFileCollection, and when do you use each?

level: seniorimportance: should knowfreq 30%

answer

  1. .elements = Provider<Set<FileSystemLocation>>
  2. wire lazily, map/flatMap, cache-safe
  3. .asFileTree = recursive FileTree view
  4. include/exclude + visit on the tree
  5. .files = eager Set<File>, exec-time only

basics

~10 s

.elements returns a Provider<Set<FileSystemLocation>> — a lazy view you can map/wire without resolving now. .asFileTree turns the collection into a FileTree so you can walk directory contents recursively and apply include/exclude patterns.

solid answer

~40 s

These are two lazy views over the same collection. **`.elements`** is a `Provider<Set<FileSystemLocation>>`: a deferred handle to the collection's contents that you can `map`/`flatMap` and feed into other lazy properties without forcing resolution at configuration time. It's the configuration-cache-friendly way to derive values (paths, names) from the collection. **`.asFileTree`** converts the collection into a `FileTree` — a *recursive* view where each directory member is expanded into its descendant files. That's what you want when you need to walk contents, apply `include`/`exclude` Ant-style patterns, `visit` files, or feed a copy/zip operation. Rule of thumb: use `.elements` to *wire* the collection into other providers lazily; use `.asFileTree` to *traverse* file contents, especially when directories must be expanded.

code

kotlin · 9 lines
kotlin
// lazy derivation, stays a Provider:
val jsonNames = sources.elements.map { locs ->
    locs.map { it.asFile.name }.filter { it.endsWith(".json") }
}

// recursive traversal with patterns:
sources.asFileTree
    .matching { include("**/*.json") }
    .visit { println(relativePath) }

go deeper

for a junior

Know .asFileTree lets you walk files with include/exclude; .elements is a lazy provider view.

for a middle

Pick correctly: .elements to wire lazily, .asFileTree to traverse/expand directories.

for a senior

Explain FileSystemLocation, why .elements preserves config-cache safety vs eager .files, and FileTree's recursive semantics.

for a principal

Codify that derived values flow through .elements/providers rather than eager .files, keeping plugin code cache-correct at scale.

## Two lazy views A `ConfigurableFileCollection` exposes derived views that stay lazy so you don't resolve files prematurely. ### `.elements` → `Provider<Set<FileSystemLocation>>` `FileSystemLocation` is the common supertype of `RegularFile` and `Directory`. `collection.elements` gives you a **`Provider`** of the set of locations — nothing is resolved until the provider is queried. Because it's a `Provider`, you can chain: ```kotlin val names: Provider<List<String>> = sources.elements.map { locs -> locs.map { it.asFile.name } } ``` This is ideal for wiring derived data into another `Property`/`@Input` while preserving laziness and configuration-cache compatibility. Avoid the eager alternative `sources.files` (a `Set<File>`) at configuration time — that forces resolution. ### `.asFileTree` → `FileTree` A **`FileTree`** is a *hierarchical* file collection: directory entries are expanded to all their descendant files, and you can filter with patterns and visit entries. `collection.asFileTree` gives you that view: ```kotlin val tree: FileTree = sources.asFileTree tree.matching { include("**/*.json"); exclude("**/tmp/**") } .visit { println(relativePath) } ``` Use it when you need to: - recurse into directories (a plain `FileCollection` lists the directory *as one entry*; a `FileTree` lists its files), - apply `include`/`exclude` glob patterns, - drive `Copy`/`Zip`/`Sync` or a custom `@TaskAction` that walks files. ## Choosing between them | Need | Use | |------|-----| | Derive a value lazily and wire it into another provider/property | `.elements` | | Walk/expand directory contents, filter by pattern, visit files | `.asFileTree` | | Eagerly get a `Set<File>` right now (execution time only) | `.files` | ## Why laziness here matters Reading `.files` during configuration resolves the whole collection and can break the configuration cache or trigger work you don't need. `.elements` keeps the value as a `Provider`, deferring resolution to execution, which is the modern, cache-safe pattern.

  • What is FileSystemLocation and why does .elements use it instead of File?
    FileSystemLocation is the lazy-API supertype of RegularFile and Directory. Using it keeps the elements view inside the lazy provider world (each location is itself a managed value), rather than collapsing to java.io.File and losing the lazy/cache semantics.
  • Why does iterating a FileCollection over a directory differ from iterating its asFileTree?
    A FileCollection treats a directory as a single element. asFileTree expands directories into all descendant files, so iterating the tree yields the individual files (and lets you apply include/exclude patterns and visit them).

saying these in an interview costs you the question

  • Saying .elements returns a Set<File> eagerly — it returns a Provider.
  • Using .files at configuration time and breaking the configuration cache.
  • Claiming a plain FileCollection recurses into directories the way a FileTree does.

context