Skip to content

[Java] @CopilotTool ergonomics 4.2: Schema generation utility (TypeMirror to JSON Schema) #1759

Description

@edburns

Overview

Create a compile-time schema generation utility that maps javax.lang.model types (TypeMirror, DeclaredType) to JSON Schema represented as Java source code literals (Map.of(...) expressions).

Branch: edburns/1682-java-tool-ergonomics on upstream (⚠️ NOT main — PRs must target this branch)

Prerequisites

  • Task 4.1 (annotations) must be complete and merged to the branch.
  • Before writing any code, read the entire implementation plan at:
    1682-java-tool-ergonomics-prompts-remove-before-merge/dd-3018003-ignorance-reduction-for-implementation-plan.md

Relevant plan sections to carefully re-read

  • Section 3.4 — Type-to-JSON-Schema mapping (Resolution: maximum viable set of 23 type mappings with full table)
  • Section 3.5 — Generated code shape (Resolution: how generated code uses schema maps)
  • Section 4.2 — Schema generation utility (compile-time) (the primary task description)

Deliverables

Files to create

  1. java/src/main/java/com/github/copilot/tool/SchemaGenerator.java

Functional specification

SchemaGenerator is a compile-time utility invoked by the annotation processor. It receives javax.lang.model.type.TypeMirror instances and produces a String containing the Java source code literal for the JSON Schema Map. For example, given a String type, it should produce the source code string: Map.of("type", "string").

Type mappings to implement (from Resolution 3.4)

Java type JSON Schema source literal
String Map.of("type", "string")
int, Integer Map.of("type", "integer")
long, Long Map.of("type", "integer")
double, Double Map.of("type", "number")
float, Float Map.of("type", "number")
boolean, Boolean Map.of("type", "boolean")
String[] Map.of("type", "array", "items", Map.of("type", "string"))
enum types Map.of("type", "string", "enum", List.of("V1", "V2", ...)) (enumerate all constants)
UUID Map.of("type", "string", "format", "uuid")
OffsetDateTime Map.of("type", "string", "format", "date-time")
JsonNode Map.of() (any)
Object Map.of() (any)
List<T>, Collection<T> Map.of("type", "array", "items", <schema-of-T>)
Map<String, String> Map.of("type", "object", "additionalProperties", Map.of("type", "string"))
Map<String, Boolean> Map.of("type", "object", "additionalProperties", Map.of("type", "boolean"))
Map<String, Long> Map.of("type", "object", "additionalProperties", Map.of("type", "integer"))
Map<String, Object> Map.of("type", "object") (opaque)
Map<String, T> (typed T) Map.of("type", "object", "additionalProperties", <schema-of-T>)
Map<String, List<String>> nested as expected
Records / POJOs Map.of("type", "object", "properties", Map.of(...), "required", List.of(...))
Sealed / @JsonSubTypes Map.of("oneOf", List.of(...)) with discriminator
Optional<T> Schema of T, excluded from required array
OptionalInt Map.of("type", "integer"), excluded from required
OptionalDouble Map.of("type", "number"), excluded from required

API design

public class SchemaGenerator {
    /**
     * Given a TypeMirror from the annotation processing environment,
     * return a String containing Java source code for a Map literal
     * representing the JSON Schema of that type.
     */
    public String generateSchemaSource(TypeMirror type, Types typeUtils, Elements elementUtils) { ... }

    /**
     * Generate the full "parameters" schema source for a method's parameters.
     * Produces a Map.of("type", "object", "properties", Map.of(...), "required", List.of(...)).
     */
    public String generateParametersSchemaSource(List<? extends VariableElement> parameters,
                                                  Types typeUtils, Elements elementUtils) { ... }
}

The class should use javax.lang.model.type.TypeKind, DeclaredType.getTypeArguments(), ElementKind.ENUM_CONSTANT, and related APIs. It does NOT use java.lang.reflect at all.

Gating tests and criteria

All of the following must pass before this task is considered complete:

  1. Unit tests: Create java/src/test/java/com/github/copilot/tool/SchemaGeneratorTest.java that tests schema generation. Since TypeMirror instances are hard to mock, use the compilation-testing approach: write small Java source snippets, compile them with javax.tools.JavaCompiler, and have a test processor that exercises SchemaGenerator during compilation. Alternatively, use a test annotation processor that logs generated schema and asserts correctness.

  2. Minimum type coverage tests: The test must verify correct schema generation for at minimum:

    • String{"type": "string"}
    • int / Integer{"type": "integer"}
    • boolean / Boolean{"type": "boolean"}
    • double / Double{"type": "number"}
    • An enum type → {"type": "string", "enum": [...]}
    • List<String>{"type": "array", "items": {"type": "string"}}
    • A simple record with 2-3 fields → {"type": "object", "properties": {...}, "required": [...]}
    • Optional<String> → schema of String, NOT in required
    • Map<String, String>{"type": "object", "additionalProperties": {"type": "string"}}
  3. Generated source validity: For each test case, verify the generated source code string is syntactically valid Java (it should compile if pasted into a method body).

  4. Spotless format check: mvn spotless:check passes.

  5. Full test suite: mvn clean verify passes (existing tests and 4.1 tests not broken).

Constraints

  • ✅✅ YOU MUST run mvn spotless:apply before every commit.

  • This class operates exclusively at compile time with javax.lang.model APIs.

  • Do NOT use java.lang.reflect anywhere in this class.

  • Do NOT modify any files outside the java/ directory.

  • Follow existing code style (4-space indent, Javadoc on public APIs).

  • The generated source code strings must use java.util.Map.of() and java.util.List.of() (Java 9+ immutable collections) for the schema literals.

Metadata

Metadata

Type

No fields configured for Task.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions