Skip to content

fix: make JsonSchemaGenerator thread-safe with caching and synchronized generation (GH-6207)#6223

Closed
suryateja-g13 wants to merge 1 commit into
spring-projects:mainfrom
suryateja-g13:gh-6207-json-schema-thread-safety
Closed

fix: make JsonSchemaGenerator thread-safe with caching and synchronized generation (GH-6207)#6223
suryateja-g13 wants to merge 1 commit into
spring-projects:mainfrom
suryateja-g13:gh-6207-json-schema-thread-safety

Conversation

@suryateja-g13
Copy link
Copy Markdown
Contributor

Summary

Fixes #6207 — concurrent calls to JsonSchemaGenerator.generateForType() / generateForMethodInput() throw ConcurrentModificationException from JsonPropertySorter inside victools' JacksonSchemaModule.

Root cause: The static SchemaGenerator instances (TYPE_SCHEMA_GENERATOR, SUBTYPE_SCHEMA_GENERATOR) are shared across threads but are not thread-safe. JacksonSchemaModule with RESPECT_JSONPROPERTY_ORDER uses a sorted property list that throws ConcurrentModificationException under concurrent access.

Fix — two-layer defense:

  1. ConcurrentHashMap caches — one per (Type, Set<SchemaOption>) for generateForType, one per (Method, Set<SchemaOption>) for generateForMethodInput. Once a schema is generated for a type it is served instantly from cache for all subsequent callers, eliminating the bulk of concurrent generator invocations.

  2. synchronized blocks around generateSchema() calls — protects the first-time generation of any given type before the result lands in cache (prevents the race for concurrent first-callers for distinct types).

The caching also provides a meaningful performance improvement: BeanOutputConverter is instantiated on every ChatClient.ResponseSpec.entity() call and invokes JsonSchemaGenerator.generateForType() each time — with this fix the expensive victools generation runs only once per type per JVM.

Test plan

  • JsonSchemaGeneratorTests.generateForTypeConcurrently — 20 virtual threads concurrently generate the same type, no CME, all results equal
  • JsonSchemaGeneratorTests.generateForMethodInputConcurrently — 20 virtual threads concurrently generate the same method schema, no CME, all results equal
  • All 36 existing JsonSchemaGeneratorTests continue to pass

…ed generation (spring-projectsGH-6207)

The shared static SchemaGenerator instances were not protected against concurrent access.
victools' JacksonSchemaModule (RESPECT_JSONPROPERTY_ORDER) maintains internal sorted state
that throws ConcurrentModificationException when multiple threads call generateSchema()
simultaneously.

Two-layer fix:
1. ConcurrentHashMap caches per (Type, Set<SchemaOption>) and (Method, Set<SchemaOption>)
   — once a schema is generated it is returned instantly for all subsequent callers of the
   same type, eliminating repeated concurrent calls entirely.
2. synchronized blocks around generateSchema() calls — protects the first-time
   concurrent generation for distinct types before the cached value is available.

Signed-off-by: Gorre Surya <suryateja.g13@gmail.com>
@suryateja-g13
Copy link
Copy Markdown
Contributor Author

Closing in favor of the earlier PRs #6216 and #6217 that address the same issue. My PR adds caching on top of synchronization, but the maintainers can decide which approach to prefer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JSON Schema Generation not thread safe - ConcurrentModificationException from Victools

1 participant