Repository navigation
Java SDK: Honor TaskFlow arg bindings sent by the supervisor - #71188
Merged
jason810496 merged 6 commits intoSep 25, 2026
Merged
Conversation
This was referenced Aug 5, 2026
jason810496
force-pushed
the
feature/java-sdk-arg-bindings-runtime
branch
2 times, most recently
from
August 13, 2026 04:25
94d41e1 to
01910ae
Compare
jason810496
force-pushed
the
feature/java-sdk-arg-bindings-runtime
branch
2 times, most recently
from
August 14, 2026 06:32
f009e18 to
a214008
Compare
FrankYang0529
approved these changes
Sep 22, 2026
FrankYang0529
left a comment
Member
There was a problem hiding this comment.
Overall LGTM. Thanks for the PR.
jason810496
commented
Sep 22, 2026
jason810496
left a comment
Member
Author
There was a problem hiding this comment.
Thanks for the review, I just addressed the comments.
henry3260
reviewed
Sep 22, 2026
henry3260
reviewed
Sep 22, 2026
henry3260
left a comment
Contributor
There was a problem hiding this comment.
Thanks, just leave few concerns
1 task done
jason810496
marked this pull request as draft
September 23, 2026 06:25
This was referenced Sep 23, 2026
A declared parameter must find an argument; a passed argument need not find a parameter. The two directions are not symmetric, and the SDK now treats them that way. - `TaskInput`: a field no argument supplies fails the task, whatever its type. Previously only a primitive field failed and a boxed or reference one silently took `null`, which hid a Java signature that had drifted from the Python stub. Once a field has claimed its argument, a null literal or an absent XCom still gives `null` to a boxed or reference field and still fails for a primitive, so declaring a boxed type stays the way to say the value is optional. A field two arguments fold onto now names the ambiguity instead of failing as if nothing matched. - `TaskInput`: an argument no field claims is logged rather than failed. The Go SDK errors here, but it has to, because its unmatched fields are silently zero-valued; Java's primitive and boxed types already say per field whether a value is required. - Positional binding: read `from_default` and drop those entries before the arity check when the counts disagree. ADR-0007 captures an unpassed parameter with its default and expects consumers to leave it unclaimed, so a method that omits a defaulted trailing parameter is not reading shifted arguments. ADR-0001 records the rule and why it differs from go-sdk ADR-0006.
jason810496
force-pushed
the
feature/java-sdk-arg-bindings-runtime
branch
from
September 23, 2026 12:25
e8b8a5e to
fd97648
Compare
jason810496
marked this pull request as ready for review
September 23, 2026 14:55
jason810496
commented
Sep 23, 2026
jason810496
left a comment
Member
Author
There was a problem hiding this comment.
Thanks for the review.
henry3260
reviewed
Sep 24, 2026
Contributor
|
Thanks for solving my comments :) |
jason810496
marked this pull request as draft
September 24, 2026 07:57
1 task done
…istration at serve A TaskInput field binds by name, so neither direction of a name mismatch can hand a task the wrong value: a field nothing supplies keeps its Java default, and an argument no field claims changes nothing the task reads. Failing the unfilled direction, as this PR did until now, made Java stricter than the Go SDK for a disagreement neither language can act on. Both directions are logged instead, with the wording the Go SDK uses. Two fields whose names fold alike still fail when the bundle is built, since the fold cannot tell them apart and neither value is safe to pick. Bundle is mutable now that registration is incremental, which left two ways to build one that cannot work: - A Dag declared in Java owns its own tasks, so its ID cannot also hold task handlers. The two kinds live in their own maps and each rejects an ID the other holds, whichever order they arrive in. Registering a handler for a Dag the Java side declared used to succeed and quietly add a task no Python file could supply arguments for. - Registration ends when Server.serve starts, so a register left below it is reported rather than racing the running task.
jason810496
force-pushed
the
feature/java-sdk-arg-bindings-runtime
branch
from
September 24, 2026 08:38
9afb19f to
ef4bb3c
Compare
jason810496
marked this pull request as ready for review
September 24, 2026 08:41
jason810496
commented
Sep 24, 2026
Member
Author
There was a problem hiding this comment.
Nice catch, both concerns are valid. TS and Go side did validate your findings.
I addressed them all in the latest commit, thanks.
Additionally, the latest commit filled the gap of mixed language task TaskFlow binding semantic like #73648.
henry3260
approved these changes
Sep 25, 2026
henry3260
left a comment
Contributor
There was a problem hiding this comment.
Thanks for the update!
This was referenced Sep 27, 2026
1 task done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The Python
@task.stubcall site already defines task data flow. Java tasks should consume those bindings directly instead of repeating upstream IDs with@Builder.XCom.The Java call site is settled by ADR-0001 (merged in #72019); this PR implements its binding half. The wire contract is ADR-0007.
Example
Three authoring syntaxes, exactly the three ADR-0001 specifies. All resolve to the same bindings.
1. Annotation based with positional injection
2. Annotation based with an explicit struct
report(run_label=..., transformed=...)binds with nothing declared — names match ignoring case and underscores:3. Interface based with an explicit
TaskInputSyntax 1 compiles to this — copied out of the example project's generated sources:
How
@Builder.TaskHandler(dag, task)names the pair a handler binds to, rather than@Builder.Task(id)inside a@Builder.Dagclass. Python declares the task and Java supplies only its body, so the two are different things and should not share a name.@Builder.Dag/@Builder.Taskare left for a Dag authored in Java (Java SDK: Declare a Dag's task graph with @Builder.Deps #71189).Bundleis created and registered into:registertakes the class a handler lives on.Client/Contexttake no position.TaskInput. A task declares flat parameters or oneTaskInput, never both.@ArgNameis for what the fold cannot reach (a Python keyword, an unusable identifier) and is matched literally.List<String>parameter or field does not arrive asList<LinkedHashMap>.TaskArgsis internal —org.apache.airflow.sdk.internal, not aTaskInput, emitted by the processor only.InputTask<TaskArgs>is a compile error; interface tasks declare aTaskInput.null; primitive inputs fail withMissingXComException, naming the stub argument.@Builder.XComis removed, keeping the Python call site as the single source of data-flow wiring.Follow-up
ADR-0001 writes the generic read as Jackson's
TypeReference<T>. This PR ships an SDK-ownedTypeRef<T>instead, because Jackson is animplementationdependency and exposing it would put Jackson on every consumer's compile classpath. Promotingjackson-coretoapiand usingTypeReferencedirectly is worth doing on its own — it is a deliberate next step, not a limitation this PR works around.ADR-0001's examples are also over-annotated under the fold:
@ArgName("run_label")on arunLabelfield is now redundant. Worth a pass over the ADR.Was generative AI tooling used to co-author this PR?