spring-projects / spring-projects/spring-ai

BeanOutputConverter .entity() ignores @Schema annotations despite documentation claiming support - forces code duplication with @JsonPropertyDescription

Open
#5,341 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: waiting-for-triage
Dominant language
Java
Stars
9.5k
Forks
2.9k
Avg merge
1d 7h
Merged PRs (30d)
6

Description

The BeanOutputConverter (used internally by .entity()) ignores Swagger/OpenAPI @Schema annotations for field descriptions, despite the official API documentation explicitly listing @Schema as a supported annotation. This forces developers to duplicate field descriptions using @JsonPropertyDescription, creating unnecessary code duplication and maintenance overhead.

Environment

  • Spring AI version: 1.1.2
  • Java version: Java 21
  • AI Provider: OpenAI

Documentation vs. Reality

According to the JsonSchemaGenerator API documentation, the following annotations are officially supported:

  • @ToolParam(required = ..., description = ...)
  • @JsonProperty(required = ...)
  • @JsonClassDescription(...)
  • @JsonPropertyDescription(...)
  • @Schema(required = ..., description = ...)
  • @Nullable

However, in practice with .entity() / BeanOutputConverter, only @JsonPropertyDescription actually works.


Steps to Reproduce

  1. Create a POJO with @Schema annotations:
import io.swagger.v3.oas.annotations.media.Schema;

public class Product {
    @Schema(description = "Unique product identifier")
    private Long id;
    
    @Schema(description = "Product name as displayed in catalog")
    private String name;
    
    @Schema(description = "Product price in USD")
    private Double price;
    
    // getters and setters
}
  1. Use structured output with .entity():
Product result = chatClient.prompt()
    .user("Extract product information: iPhone 15 Pro, $999")
    .call()
    .entity(Product.class);
  1. Debug the generated schema:
BeanOutputConverter<Product> converter = new BeanOutputConverter<>(Product.class);
System.out.println(converter.getFormat());

Expected Behavior

The generated JSON schema should include description fields from @Schema annotations:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": {
      "type": "integer",
      "description": "Unique product identifier"
    },
    "name": {
      "type": "string",
      "description": "Product name as displayed in catalog"
    },
    "price": {
      "type": "number",
      "description": "Product price in USD"
    }
  }
}

Actual Behavior

The generated schema completely omits all description fields:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": {"type": "integer"},
    "name": {"type": "string"},
    "price": {"type": "number"}
  }
}

Current Workaround (Code Duplication Problem)

The only way to make descriptions work is to use @JsonPropertyDescription:

import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import io.swagger.v3.oas.annotations.media.Schema;

public class Product {
    // For OpenAPI/Swagger documentation
    @Schema(description = "Unique product identifier")
    
    // For Spring AI structured output - DUPLICATE!
    @JsonPropertyDescription("Unique product identifier")
    private Long id;
    
    @Schema(description = "Product name as displayed in catalog")
    @JsonPropertyDescription("Product name as displayed in catalog")
    private String name;
    
    @Schema(description = "Product price in USD")
    @JsonPropertyDescription("Product price in USD")
    private Double price;
}

This creates several problems:

  1. Code duplication - Same description text written twice on every field
  2. Maintenance burden - Description changes must be updated in two places
  3. Inconsistency risk - Descriptions can drift out of sync between annotations
  4. Documentation mismatch - Contradicts the official API documentation that claims @Schema is supported
  5. Ecosystem fragmentation - Forces different annotation strategies for OpenAPI docs vs AI structured outputs

Impact

This issue affects any Spring Boot application that uses both:

  • OpenAPI/Swagger for API documentation (@Schema)
  • Spring AI for structured outputs (.entity())

These are very common use cases in modern Spring Boot applications, making this a significant pain point.


Related Issues

  • #738 - Similar request for field description support (closed without resolution)
  • #4487 - Similar issue with MCP Tools ignoring Jackson annotations

Both issues point to inconsistencies in JsonSchemaGenerator's annotation handling.


Proposed Solution

Ensure JsonSchemaGenerator.internalGenerateFromClass includes the Swagger/OpenAPI module in its schema generation configuration, making @Schema annotations work consistently across:

  • Function calling / tool parameters
  • MCP tool schemas
  • Structured outputs via .entity() / BeanOutputConverter ← Currently broken

This would allow developers to use a single, consistent annotation strategy across their entire codebase.


Additional Context

Many Spring Boot developers already use @Schema extensively for OpenAPI documentation. Having to duplicate these annotations with @JsonPropertyDescription just for AI structured outputs creates unnecessary friction and goes against DRY principles.

The documentation explicitly states @Schema is supported, so this appears to be a bug rather than an intended limitation.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at JsonSchemaGenerator.internalGenerateFromClass and trace how BeanOutputConverter builds its schema; compare the documented supported annotations with the generated schema from the reproduction. Done means @Schema descriptions appear in .entity() output without duplicating @JsonPropertyDescription.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, openapi, spring-boot
Domain
api, backend-api-design
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.