azure/azure-sdk-for-java/union-type-wrappers
- community
Checking that the SKILL.md file is still in the repository.
Add typed getters and setters over BinaryData properties that represent TypeSpec union types in generated Java models. Use when generated classes expose BinaryData for union-typed fields and you need ergonomic, type-safe accessors instead.
Install
npx vskill@latest install azure/azure-sdk-for-java/union-type-wrappersSKILL.md
Union Type Wrappers for Generated Java Models
When the Java codegen encounters a TypeSpec union type (e.g. string | SomeModel), it emits the property as BinaryData. This skill replaces public BinaryData accessors with typed setters and getters for each union variant, following the same pattern established for PromptAgentDefinition.toolChoice.
Preconditions
- You must be in a Java SDK module directory containing
tsp-location.yamlandpom.xml. - TypeSpec sources must be available in
TempTypeSpecFiles/. If missing, runtsp-client syncfirst. - The project must compile before starting.
Important: BinaryData.writeTo(JsonWriter) semantics
Understanding how BinaryData writes to JSON is critical for choosing the correct factory method:
| Factory method | Content type | writeTo(JsonWriter) calls | JSON output | |
|---|---|---|---|---|
BinaryData.fromString("auto") | StringContent | jsonWriter.writeString("auto") | "auto" (quoted) | |
BinaryData.fromObject("auto") | SerializableContent | jsonWriter.writeRawValue(...) | "auto" (quoted via Jackson) | |
BinaryData.fromObject(42.0) | SerializableContent | jsonWriter.writeRawValue(...) | 42.0 (raw) | |
BinaryData.fromObject(true) | SerializableContent | jsonWriter.writeRawValue(...) | true (raw) | |
BinaryData.fromObject(jsonSerializable) | SerializableContent | jsonWriter.writeRawValue(...) | {...} (JSON object via JacksonAdapter) |
Key: JacksonAdapter has special handling for JsonSerializable types — BinaryData.fromObject() and BinaryData.toObject() both work correctly with Azure JsonSerializable models.
Setter factory method rules
| Union variant | Factory method | Reason | |
|---|---|---|---|
| String value (ID, enum token) | BinaryData.fromString(value) | Writes as JSON string via writeString() | |
| Numeric / boolean primitive | BinaryData.fromObject(value) | Writes as raw JSON value | |
Azure JsonSerializable model | BinaryData.fromObject(value) | JacksonAdapter handles serialization | |
| Stainless (openai-java) type | BinaryData.fromObject(value) | Jackson handles serialization |
Getter deserialization rules
| Union variant | Deserialization | Notes | |
|---|---|---|---|
| String | this.field.toObject(String.class) | Consistent regardless of how BinaryData was created (fromString vs fromObject during deserialization) | |
| Primitive (Number, Boolean) | this.field.toObject(Double.class) etc. | Jackson deserializes raw JSON values | |
Azure JsonSerializable model | this.field.toObject(ModelClass.class) | JacksonAdapter calls fromJson() | |
| Stainless type | this.field.toObject(StainlessType.class) | Jackson deserializes natively |
Workflow
1. Scan for BinaryData properties
Find all BinaryData fields in generated model classes:
Exclude List<BinaryData> and Map<..., BinaryData> from this pass — those are collection-of-union patterns that require separate handling.
2. Cross-reference against TypeSpec
For each BinaryData property found, determine whether it comes from a union type or an `unknown` type:
- Union type (
type_a | type_b): Proceed with this skill. - `unknown` type: Leave as
BinaryData— this is the correct representation.
Also check client.tsp for any @@changePropertyType overrides that may have already flattened the union to string (like tool_choice).
3. Identify the union variants
For each union type, determine what types the property can hold. Sources:
- Local TSP files — look at the type definition in
TempTypeSpecFiles/. - Stainless SDK JAR — if the union comes from
OpenAI.*, inspect the Stainless types:
``bash jar tf ~/.m2/repository/com/openai/openai-java-core/<version>/openai-java-core-<version>.jar | grep "<TypeName>" javap -cp <jar> "com.openai.models.responses.<OuterClass>\$<InnerUnion>" ``
- Generated Azure models — check if the Azure SDK already generates the variant model classes (e.g.
AutoCodeInterpreterToolParam,McpToolFilter).
4. Apply changes to the model class
For each union-typed BinaryData property, apply the following pattern:
4a. Leave the property field as-is
Do not modify the property declaration. Keep @Generated, the block comment, and the visibility exactly as the codegen produced them. The field is already private — there is nothing to change.
4b. Make the existing getter and setter package-private
- Remove
@Generated. - Change visibility to package-private (no access modifier). This keeps them hidden from SDK consumers but accessible to unit tests in the same package.
- Keep the original method name — do NOT rename to
*Internal. - Keep the original javadoc intact.
- Add
// AI Tooling: union typeas the first line inside the method body.
For `@Immutable` classes (value is a constructor param):
- Change the
BinaryDataconstructor visibility to package-private (keep forfromJsondeserialization). - Add public constructor overloads for each variant.
- Make the
BinaryDatagetter private.
4c. Add typed setters (one per union variant)
Naming convention: `set<PropertyName>(<VariantType> value)` — use method overloading.
Copy the javadoc from the original generated setter, adapting the @param description to the specific variant type. Add // AI Tooling: union type as the first line inside the method body.
When overloading isn't possible (e.g. two different String meanings), disambiguate with parameter names and javadoc.
For List<String> variants:
4d. Add typed getters (one per union variant)
Naming convention: `get<PropertyName>As<TypeName>()`
Copy the javadoc from the original generated getter, adapting the @return description. Add // AI Tooling: union type as the first line inside the method body.
For List<String> variants:
5. Update callers
Search for existing code that uses the old BinaryData API:
Update samples, tests, and internal code to use the new typed API. Remove unused BinaryData imports where applicable.
6. Write unit tests
Create a test class per model under src/test/java/.../models/<ModelName>SerializationTests.java.
Each test class must include:
- Serialization tests — one per union variant. Construct the model with the typed setter, serialize to JSON, assert the JSON contains the expected field and value.
- Deserialization tests — one per union variant. Parse a JSON string, assert the typed getter returns the correct value.
- Null/absent tests — verify getters return
nullwhen the field is not set or absent from JSON. - Round-trip tests — serialize → deserialize → assert values match.
Use these helpers:
7. Compile and run tests
All tests must pass before finishing.
Checklist
Before reporting completion, verify:
- [ ] Every
BinaryDataproperty was classified as union or unknown - [ ] Property fields left exactly as generated (no modifications)
- [ ] Original
BinaryDatagetter/setter made package-private, name kept,@Generatedremoved, javadoc preserved - [ ]
// AI Tooling: union typeplaced inside the body of every modified or added getter/setter - [ ] Typed setters added for each union variant with javadoc copied from original
- [ ] Typed getters added for each union variant (
get*As*()) with javadoc copied from original - [ ] All callers (samples, tests, internal code) updated to use new API
- [ ] Unused
BinaryDataimports removed from callers - [ ] Unit tests written and passing for serialization, deserialization, null, and round-trip
- [ ] Full compilation succeeds (main + test + samples)
Troubleshooting
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 95 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingsdk/ai/.workflow_docs/union-type-wrappers/SKILL.md
Popularity
- Repository stars
- 2,562
- Repository forks
- 2,202
- 7-day trend score
- 44
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/azure/azure-sdk-for-java/union-type-wrappers)