diff --git a/spring-ai-model/src/main/java/org/springframework/ai/util/json/schema/JsonSchemaGenerator.java b/spring-ai-model/src/main/java/org/springframework/ai/util/json/schema/JsonSchemaGenerator.java index 036fca1216..c9fd4056d3 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/util/json/schema/JsonSchemaGenerator.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/util/json/schema/JsonSchemaGenerator.java @@ -90,7 +90,8 @@ public final class JsonSchemaGenerator { * Initialize JSON Schema generators. */ static { - Module jacksonModule = new JacksonSchemaModule(JacksonOption.RESPECT_JSONPROPERTY_REQUIRED); + Module jacksonModule = new JacksonSchemaModule(JacksonOption.RESPECT_JSONPROPERTY_REQUIRED, + JacksonOption.RESPECT_JSONPROPERTY_ORDER); Module openApiModule = new Swagger2Module(); Module springAiSchemaModule = PROPERTY_REQUIRED_BY_DEFAULT ? new SpringAiSchemaModule() : new SpringAiSchemaModule(SpringAiSchemaModule.Option.PROPERTY_REQUIRED_FALSE_BY_DEFAULT); diff --git a/spring-ai-model/src/test/java/org/springframework/ai/util/json/JsonSchemaGeneratorTests.java b/spring-ai-model/src/test/java/org/springframework/ai/util/json/JsonSchemaGeneratorTests.java index 4bedc5677e..b004d38e32 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/util/json/JsonSchemaGeneratorTests.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/util/json/JsonSchemaGeneratorTests.java @@ -26,6 +26,7 @@ import com.fasterxml.jackson.annotation.JsonClassDescription; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; import io.swagger.v3.oas.annotations.media.Schema; import org.junit.jupiter.api.Test; import tools.jackson.databind.JsonNode; @@ -700,6 +701,17 @@ void throwExceptionWhenTypeIsNull() { .hasMessage("type cannot be null"); } + @Test + void generateSchemaForTypeRespectsJsonPropertyOrder() throws Exception { + String schema = JsonSchemaGenerator.generateForType(OrderedPerson.class); + JsonNode schemaNode = JsonParser.getJsonMapper().readTree(schema); + JsonNode properties = schemaNode.get("properties"); + + assertThat(properties).isNotNull(); + List fieldNames = new java.util.ArrayList<>(properties.propertyNames()); + assertThat(fieldNames).containsExactly("name", "email", "id"); + } + static class TestMethods { public void simpleMethod(String name, int age) { @@ -775,6 +787,41 @@ record JSpecifyNullablePerson(int id, String name, @org.jspecify.annotations.Nul } + @JsonPropertyOrder({ "name", "email", "id" }) + static class OrderedPerson { + + private int id; + + private String name; + + private String email; + + public int getId() { + return this.id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return this.email; + } + + public void setEmail(String email) { + this.email = email; + } + + } + static class Person { private int id;