[java][bidi] Add BiDi code generator - #17777
Conversation
PR Summary by QodoAdd Bazel-based Java BiDi protocol code generator
AI Description
Diagram
High-Level Assessment
Files changed (21)
|
Code Review by Qodo
Context used✅ Compliance rules (platform):
18 rules 1.
|
|
I started reviewing this and ended up creating #17786 |
Code Review by Qodo
Context used✅ Compliance rules (platform):
18 rules 1. Void events never dispatched
|
|
Code review by qodo was updated up to the latest commit 7b9799f |
|
Code review by qodo was updated up to the latest commit 1760de4 |
|
Code review by qodo was updated up to the latest commit 1f4ec87 |
| ], | ||
| ) | ||
|
|
||
| genrule( |
There was a problem hiding this comment.
1. Unquoted genrule arguments 🐞 Bug ☼ Reliability
The new :generate-bidi genrule builds a shell command without quoting the tool path, schema path, or output path, so the action can fail when any of those paths contain spaces or shell-special characters. This makes BiDi generation brittle and can break Bazel builds depending on workspace/execroot location.
Agent Prompt
### Issue description
The `genrule(name = "generate-bidi")` command concatenates `$(execpath ...)`, `$(location ...)`, and `$@` into a shell command without quoting. If any expanded path contains whitespace or shell-special characters, the generator will receive split/incorrect arguments and the build will fail.
### Issue Context
This genrule is new in this PR and is used to generate `bidi-generated.srcjar` during the build.
### Fix Focus Areas
- java/src/org/openqa/selenium/bidi/BUILD.bazel[59-65]
### Suggested fix
Update `cmd` to quote each argument as a single shell token, e.g.:
```bzl
cmd = "\"$(execpath :bidi-client-generator)\" \"$(location //javascript/selenium-webdriver:create-bidi-src_schema)\" \"$@\"",
```
(or equivalent quoting per the repo’s Bazel shell conventions), so paths with spaces are handled correctly.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
|
Code review by qodo was updated up to the latest commit 3d4a143 |
|
Good progress. Heads up in case you missed it, #17784 added the preserveExtras signal to the projected schema (alongside the existing extensible), so extensibility is now fully derivable per-type: extensible marks the open types, and preserveExtras is pre-scoped to the ones that are both extensible and re-sendable so you don't have to work out that scoping in the generator. |
3d4a143 to
a2fa95c
Compare
| handle.unsubscribe(subscriptionId); | ||
| } | ||
| } | ||
| } No newline at end of file |
There was a problem hiding this comment.
1. Missing trailing newline 🐞 Bug ⚙ Maintainability
Module.java now ends without a final newline, which can violate standard source formatting conventions and can trip formatting/lint checks in some environments.
Agent Prompt
### Issue description
`java/src/org/openqa/selenium/bidi/Module.java` ends without a trailing newline.
### Issue Context
The PR diff explicitly indicates `No newline at end of file` on the final `}`.
### Fix Focus Areas
- java/src/org/openqa/selenium/bidi/Module.java[68-68]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
|
Code review by qodo was updated up to the latest commit 7e5e00c |
🔗 Related Issues
💥 What does this PR do?
Adds the BiDi Java client generator: reads the shared, binding-neutral BiDi schema and emits the full typed Java BiDi protocol layer — module classes (one per domain, with commands and events) plus supporting POJOs, enums, and discriminated unions — across all 14 domains (~79 commands, 27 events, 298 generated classes total), on top of the hand-written seam (Module base class + Handle) that makes it usable.
Shape of a generated module class (real output, network.Network trimmed to 2 events + 2 commands — the full file has 5 events and 13 commands):
Usage is symmetric regardless of whether a command has a result:
🔧 Implementation Notes
Autogenerated code and not checked in
The build compiles the genrule's srcjar directly:
No generated
.javais ever committed.Trade-off accepted knowingly: less reviewable diff surface for generator changes. Given Java has a lot of generated classes, strict typing means one
.javafile per record/enum/union, not a handful of dynamically-typed modules like the JS or Python bindings. The actual generated code never appears in this PR's diff, only the generator that produces it.How to see the generated output since it's not in the diff, pull it out locally:
bazel build //java/src/org/openqa/selenium/bidi:bidi-generated mkdir -p /tmp/bidi-generated-src unzip -o -q bazel-bin/java/src/org/openqa/selenium/bidi/bidi-generated.srcjar -d /tmp/bidi-generated-src open /tmp/bidi-generated-src # or just browse/grep it298 files across 14 domains will land there. A few worth spot-checking first, each demonstrating a specific decision from the Implementation Notes above:
org/openqa/selenium/bidi/protocol/module/Network.java— a representative module class (commands + events)org/openqa/selenium/bidi/protocol/browsingcontext/SetViewportParameters.java— explicit-null vs. omitted-key handling side by side (viewport/devicePixelRatioare nullable,context/userContextsaren't)org/openqa/selenium/bidi/protocol/emulation/SetTimezoneOverrideParameters.java— required-but-nullable field on a sender typeorg/openqa/selenium/bidi/protocol/script/PrimitiveProtocolValue.javaandStringValue.java— theinterface extends/implementschain for multi-parent unionsIf you'd rather regenerate directly without the Bazel packaging step (useful for diffing output after a generator change):
bazel build //java/src/org/openqa/selenium/bidi:bidi-client-generator bazel run //java/src/org/openqa/selenium/bidi:bidi-client-generator -- \ "$(bazel info bazel-genfiles)/javascript/selenium-webdriver/create-bidi-src_schema.json" \ /tmp/bidi-out.srcjar unzip -o -q /tmp/bidi-out.srcjar -d /tmp/bidi-generated-src(Direct invocation of the built binary without
bazel runfails withCannot locate runfiles directory— it needsbazel runto set up its runfiles tree.)Explicit-null vs. omitted-key tracking
Tracked per-field for fields the schema marks nullable, so
toMap()can distinguish:"field": null→ clear itThis is gated strictly on the schema's own
nullableflag, not applied blanket to every optional field.Required-but-nullable fields
@Nullableon their constructor parameter (boxed, if the field would otherwise be a Java primitive).ConstructorCoercerwas extended to honor jspecify's@Nullable(previously onlyOptional<T>was treated as nullable).🤖 AI assistance
💡 Additional Considerations
Test coverage is not uniform across domains.
Only network, log, script, and browsingContext have dedicated generated-code tests (unit and/or browser-integration) added in this PR.
session, browser, emulation, storage, input, webExtension, permissions, speculation, bluetooth, userAgentClientHints have none yet.
Essentially, the modules that are needed for implementing high-level APIs for Selenium 5 have tests.
Extensible/unknown-key round-tripping (unrecognized JSON keys silently dropped) is a known, scoped gap, not implemented in this PR. Not implemented because ConstructorCoercer maps JSON keys 1:1 to constructor parameters and silently drops anything unmatched — supporting round-trip needs a genuinely different deserialization path (capturing unrecognized keys into a side bag alongside the typed fields), which is new mechanism work, and fairly big. So this is something we might not support in Java at all. We can see how much this is required and decide later.
Rest, will be added in a follow up PR.
🔄 Types of changes