skip to content

Explain OperationType in the Tooling API events package and how it controls which build events you receive.

level: middleimportance: must knowfreq 35%

answer

  1. org.gradle.tooling.events.OperationType
  2. subscription filter, not post-filter
  3. TASK/TEST/PROJECT_CONFIGURATION/WORK_ITEM/TRANSFORM/FILE_DOWNLOAD
  4. typed subtypes per category
  5. older daemons omit newer types

basics

~10 s

OperationType is an enum (TASK, TEST, PROJECT_CONFIGURATION, etc.) you pass to addProgressListener. Gradle only delivers events whose category you subscribed to, so you filter the stream at registration time.

solid answer

~40 s

`OperationType` lives in `org.gradle.tooling.events` and categorizes the operations Gradle reports: `TASK`, `TEST`, `PROJECT_CONFIGURATION`, `WORK_ITEM`, `TRANSFORM`, `FILE_DOWNLOAD`, `BUILD_PHASE`, and `GENERIC`, among others. You pass the types you care about to `addProgressListener(listener, OperationType...)`; Gradle then only invokes your listener for events in those categories. This is a subscription filter, not a post-hoc filter — narrowing it reduces the event volume crossing the process boundary. The events you receive are still the typed subtypes: subscribing to `TASK` yields `TaskStartEvent`/`TaskFinishEvent` with a `TaskOperationDescriptor`, while `TEST` yields `TestStartEvent`/`TestFinishEvent` with a `JvmTestOperationDescriptor`. If you want everything, pass all values (e.g. `OperationType.values()`), but for an IDE you typically subscribe only to what a given UI pane renders. Newer operation types were added across Gradle versions, so older daemons may simply never emit some categories.

code

kotlin · 10 lines
kotlin
// Subscribe narrowly to drive a test-runner pane only
launcher.addProgressListener(
    ProgressListener { event ->
        if (event is TestFinishEvent) {
            val result = event.result // TestSuccessResult / TestFailureResult / TestSkippedResult
            reportTestResult(event.descriptor as JvmTestOperationDescriptor, result)
        }
    },
    OperationType.TEST
)

go deeper

for a junior

Name a few OperationType values and that you pass them to addProgressListener.

for a middle

Explain it as a subscription filter, list the main categories, and map each to its typed event/descriptor.

for a senior

Discuss event-volume/perf implications of broad subscriptions and the descriptor/result types per category.

for a principal

Address cross-version compatibility: newer client + older daemon means some categories never arrive, and how tools degrade gracefully.

## The role of OperationType `OperationType` is an enum in `org.gradle.tooling.events` that names the *kinds* of operations Gradle can report progress for. When you register a structured `ProgressListener`, you pass one or more `OperationType` values, and Gradle uses them as a **subscription filter** — you only get events for the categories you asked for. ## The common values - **`TASK`** — task execution; yields `TaskStartEvent`/`TaskFinishEvent`, descriptor `TaskOperationDescriptor` (task path, etc.). `TaskFinishEvent` results distinguish success, failure, up-to-date, from-cache, skipped, no-source. - **`TEST`** — test execution; `TestStartEvent`/`TestFinishEvent`, descriptor `JvmTestOperationDescriptor` (suite/class/method). Used to drive the IDE test runner tree. - **`PROJECT_CONFIGURATION`** — the configuration phase of each project; lets the IDE show configuration progress before tasks run. - **`WORK_ITEM`** — units submitted to the Worker API. - **`TRANSFORM`** — artifact transform executions. - **`FILE_DOWNLOAD`** — dependency/file downloads. - **`BUILD_PHASE`** — coarse build phases. - **`GENERIC`** — catch-all progress not otherwise categorized. ## Why filter at subscription time Every delivered event crosses the daemon→client boundary and is dispatched on Gradle's thread. Subscribing only to `TASK` and `TEST` (for example) keeps the stream small and your `statusChanged` switch simple. A logging-progress UI might subscribe broadly; a test runner pane subscribes to `TEST` only. ```kotlin launcher.addProgressListener( listener, OperationType.PROJECT_CONFIGURATION, OperationType.TASK ) ``` ## Version considerations New `OperationType` values were introduced over time (e.g. file-download and build-phase events in later 7.x/8.x releases). If the connected Gradle version predates a type, it simply never emits those events — your listener must not assume any particular category will appear. This is part of the Tooling API's cross-version compatibility contract: a newer client can talk to an older daemon, but only gets the events that daemon knows how to produce.

  • If you subscribe to OperationType.TEST, what concrete event types do you receive?
    TestStartEvent and TestFinishEvent, each carrying a JvmTestOperationDescriptor; the finish event also carries a TestOperationResult (success/failure/skipped).
  • What happens if you subscribe to an OperationType the connected Gradle version doesn't support?
    Nothing breaks — that older daemon simply never emits events of that category, so your listener just won't be called for it. The Tooling API tolerates the version gap.

saying these in an interview costs you the question

  • Saying OperationType filters events after they're produced — it's a subscription that controls what Gradle emits to you.
  • Assuming every OperationType is available on every Gradle version.

context