$npx -y skills add astronomer/agents --skill deploying-java-sdk-bundlesBuilds and deploys compiled Airflow Java SDK bundles so workers can run them. Use when the user wants to package a JVM task bundle into a JAR, asks about the org.apache.airflow.sdk Gradle plugin, ./gradlew bundle, the Maven shade/BOM setup, fat vs thin JARs, the logging integ
| 1 | # Deploying Java SDK Bundles |
| 2 | |
| 3 | A Java SDK deployment has one artifact: a **bundle** — your compiled task classes plus the SDK, packaged as a JAR (or a thin JAR alongside its dependency JARs). You build it with Gradle or Maven, then place it in a directory that the `JavaCoordinator` scans (`jars_root`) on every worker. This skill is platform-neutral; it shows the build once, then both an open-source and an Astro deployment path. |
| 4 | |
| 5 | > **Experimental.** The Java SDK is in preview. Artifact versions below are shown as `${version}`; while the SDK is pre-release you may need to build the artifacts into your local Maven repository yourself (see the preview builds section). |
| 6 | |
| 7 | > **Order of operations:** build the bundle (this skill) → place it where `jars_root` points → configure the coordinator (**configuring-airflow-language-sdks**). The task code itself is **authoring-java-sdk-tasks**. |
| 8 | |
| 9 | --- |
| 10 | |
| 11 | ## Build with Gradle (recommended) |
| 12 | |
| 13 | Apply the SDK's Gradle plugin and declare dependencies in `build.gradle`: |
| 14 | |
| 15 | ```groovy |
| 16 | plugins { |
| 17 | id("org.apache.airflow.sdk") version "${version}" |
| 18 | } |
| 19 | |
| 20 | repositories { |
| 21 | mavenCentral() |
| 22 | } |
| 23 | |
| 24 | dependencies { |
| 25 | annotationProcessor("org.apache.airflow:airflow-sdk-processor:${version}") // annotation API only |
| 26 | implementation("org.apache.airflow:airflow-sdk:${version}") |
| 27 | // Optional logging integration, e.g.: |
| 28 | // implementation("org.apache.airflow:airflow-sdk-jpl:${version}") |
| 29 | } |
| 30 | |
| 31 | airflowBundle { |
| 32 | mainClass = "com.example.Main" // your BundleBuilder entry point |
| 33 | // fatJar = false // opt out of the single-JAR build (see below) |
| 34 | } |
| 35 | ``` |
| 36 | |
| 37 | Build it: |
| 38 | |
| 39 | ```bash |
| 40 | ./gradlew bundle |
| 41 | ``` |
| 42 | |
| 43 | The `build/bundle/` directory then holds all required JAR(s). Notes: |
| 44 | |
| 45 | - The `annotationProcessor` line is needed **only if you use the annotation-based API**. The interface-based API doesn't need it. |
| 46 | - By default the plugin produces a **fat JAR** (via the Shadow plugin) — one self-contained file, which avoids cross-project dependency clashes. Set `fatJar = false` in `airflowBundle` for thin JARs; you then deploy every dependency JAR too. |
| 47 | - The Gradle plugin validates that `mainClass` exists at build time (`verifyBundleMainClass`). |
| 48 | |
| 49 | --- |
| 50 | |
| 51 | ## Build with Maven |
| 52 | |
| 53 | Import the BOM so artifact versions and the supervisor schema version are managed in one place: |
| 54 | |
| 55 | ```xml |
| 56 | <dependencyManagement> |
| 57 | <dependencies> |
| 58 | <dependency> |
| 59 | <groupId>org.apache.airflow</groupId> |
| 60 | <artifactId>airflow-sdk-bom</artifactId> |
| 61 | <version>${version}</version> |
| 62 | <type>pom</type> |
| 63 | <scope>import</scope> |
| 64 | </dependency> |
| 65 | </dependencies> |
| 66 | </dependencyManagement> |
| 67 | |
| 68 | <dependencies> |
| 69 | <dependency> |
| 70 | <groupId>org.apache.airflow</groupId> |
| 71 | <artifactId>airflow-sdk</artifactId> <!-- version from the BOM --> |
| 72 | </dependency> |
| 73 | </dependencies> |
| 74 | ``` |
| 75 | |
| 76 | Wire the annotation processor through `maven-compiler-plugin` (annotation API only) so it stays off the runtime classpath. Then pick a packaging option: |
| 77 | |
| 78 | - **Fat JAR (recommended):** use `maven-shade-plugin`. In its `ManifestResourceTransformer`, set `<mainClass>` to your `BundleBuilder` and add the manifest entry `Airflow-Supervisor-Schema-Version` resolved from the BOM property `${airflow.supervisor.schema.version}` (don't hard-code it). `mvn package` writes the JAR to `target/`. |
| 79 | - **Thin JAR:** use `maven-jar-plugin` to set `Main-Class` and `maven-dependency-plugin` (`copy-dependencies`) to collect runtime JARs into `target/bundle/`. Here `Airflow-Supervisor-Schema-Version` is not needed — Airflow reads it from the `airflow-sdk` JAR on the classpath. |
| 80 | |
| 81 | Unlike Gradle, Maven does **not** validate `mainClass` at build time; a wrong value only fails at runtime. |
| 82 | |
| 83 | --- |
| 84 | |
| 85 | ## Logging integration |
| 86 | |
| 87 | For task log records to reach Airflow's log store (and the task log view in the UI), the bundle must include **exactly one** SDK logging artifact per logging facade you use. Versions are managed by `airflow-sdk-bom`; Maven users apply the same artifact IDs. |
| 88 | |
| 89 | **Choosing a facade.** For a greenfield project, prefer JPL (`System.Logger`) — it is built into the JDK, so your tasks need no extra logging API. Pick another facade only when the libraries you integrate with already log through it, so their records reach Airflow too. Preference order: JPL > SLF4J = Log4j 2 > JUL; treat JUL as legacy integration only, not a choice for new code. |
| 90 | |
| 91 | | Facade | Artifact | Setup beyond the dependency | |
| 92 | |--------|------- |