This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.
@azure-tools/typespec-java is the branded Java emitter. It wraps the unbranded emitter
@typespec/http-client-java, which lives in the core/ submodule at
core/packages/http-client-java.
Only src/options.ts (the Azure-specific emitter options) is committed in this package. The rest of
the emitter TypeScript (and tests) is copied from core/packages/http-client-java/emitter/{src,test}
at build time by Copy-Sources.ps1 (excluding options.ts). The Java emitter.jar is
built by Build-Generator.ps1 from a patched copy of core/packages/http-client-java/generator
(see below) and staged into generator/http-client-generator/target/.
Copy-Sources.ps1 copies the Java generator sources out of the core/ submodule into this
package's ./generator folder and applies core.patch to that copy — never to core/ itself.
The patch swaps the unbranded customization engine in http-client-generator-core for Azure's
com.azure.tools:azure-autorest-customization (resolved from Maven Central), so the
customization-class emitter option runs against the Azure customization base. Build-Generator.ps1
then builds emitter.jar from the patched ./generator. Because the patch is only ever applied to
the copy, the core/ submodule working tree stays clean. When the core/ submodule is bumped,
refresh core.patch if its context no longer applies.
# From the repo root, install workspace dependencies.
pnpm install
# From the repo root, build typespec-java along with all its dependencies.
# Use run-all so pnpm does not auto-install concurrently during the Turbo build.
pnpm run-all --filter "@azure-tools/typespec-java..." buildCopy-Sources.ps1 reads the emitter/generator sources from the core/ submodule's current checkout.
The optional core-commit.json pins a specific upstream core commit to read from instead:
{ "sha": "3cb616e4e8c3d5b6954bac9832b97445450a71af" }The pinned SHA is fetched if needed and used only when it is newer than the current checkout (the
submodule never moves backwards). When the pin is newer, those sources are extracted from that commit
into a temporary directory via git archive — the core/ submodule is never checked out or
otherwise modified. This keeps pnpm build safe to run alongside the parallel monorepo build (which
reads core/ concurrently) and keeps CI git-status checks clean. To advance the pin, update the
sha.
If pnpm turbo ... fails with 'turbo' is not recognized as an internal or external command
after pnpm install, the local install tree is missing Turbo's binary shim. From the repo root,
force pnpm to refresh the local install state and rerun the command:
pnpm install --force
pnpm run-all --filter "@azure-tools/typespec-java..." buildChanging the npm registry has been observed to clear this symptom, possibly because pnpm re-resolves packages or relinks local binaries after the registry setting changes.
Build the package first, then run the TypeSpec compiler under the Node.js debugger from
packages/typespec-java:
node --inspect-brk node_modules/@typespec/compiler/dist/src/core/cli/cli.js compile emitter-tests/<tsp-file>Attach a debugger to port 9229 and set breakpoints in src/emitter.ts,
src/code-model-builder.ts, or their compiled counterparts under dist/src.
TypeScript passes the code model and emitter options to Java through the generated
emitter-tests/tsp-output/code-model.yaml file. To debug the Java generator directly:
-
Build the package so
Copy-Sources.ps1creates the patched generator copy undergenerator/. -
Update
DEFAULT_OUTPUT_DIRingenerator/http-client-generator/src/main/java/com/microsoft/typespec/http/client/generator/Main.javato the directory containing thecode-model.yamlto debug. -
Run
com.microsoft.typespec.http.client.generator.Main.main()from an IDE with these VM options:--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
The copied generator is recreated on each build, so do not commit changes under generator/.
Emitter options used by Main are defined in
generator/http-client-generator/src/main/java/com/microsoft/typespec/http/client/generator/model/EmitterOptions.java.
When debugging this way, temporarily align them with the options in the relevant tspconfig.yaml;
for example, set flavor to azure.
Make sure to run the following commands:
pnpm format
Shipping a @azure-tools/typespec-java patch is done as two separate PRs, both targeting the
release/<sprint> branch. The overall publishing flow is the repo's general one — see the root
CONTRIBUTING.md "Publishing" section and the
hotfix-release skill; only the
typespec-java-specific parts are called out here.
Pulls the fix in from core; no version bump. Example:
#5012. On a branch off release/<sprint>:
- Pin the core commit. Release branches don't carry
core/submodule updates, so update theshaincore-commit.jsonto the target microsoft/typespec commit (e.g. the HEAD of coremain). Build and sync scripts transiently check this commit out without moving the submodule pointer. - Sync tests from core. Run
pwsh ./SyncTests.ps1inemitter-tests: it copies the tests/specs from the pinned core commit and alignsemitter-tests/package.json. - Add a
fixchangelog entry for the fix (pnpm change add).
Open the PR against release/<sprint> (not main) and merge it. (Optional) Before merging,
validate SDK regeneration from the PR's emitter with the
typespec-java - sync sdk
pipeline: leave Emitter Version as none and set PR Id or Branch to this PR.
Bumps the version and publishes, after Part A merges. Example:
#4990. Prepare the version bump per the
hotfix-release skill (creates the publish/hotfix/<name>-<sprint> branch off release/<sprint>
and runs pnpm chronus version --ignore-policies, consuming the changeset from Part A). The core
submodule stays unchanged. The bump must also be reflected in emitter-tests/package.json (its
version and the *.tgz dependency) — rerun pwsh ./SyncTests.ps1 or update it manually.
Open the PR against release/<sprint>. After it merges:
- The emitter is auto-released by the
typespec-azure - Publishpipeline. - Backmerge the generated branch to
main. If the backmerge branch isn't created automatically (e.g. the workflow failed on a name collision), create it manually from the release branch and open the PR tomainyourself. - (Optional) Regenerate the downstream SDKs by rerunning
typespec-java - sync sdkwith Emitter Version set to the released version, and merge the resulting SDK PR.
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.