Skip to content

fix: make the deprecated annotations registry thread safe - #3402

Open
awinishere wants to merge 1 commit into
springdoc:mainfrom
awinishere:fix/deprecated-annotations-copy-on-write#3400
Open

awinishere wants to merge 1 commit into
springdoc:mainfrom
awinishere:fix/deprecated-annotations-copy-on-write#3400

Conversation

@awinishere

@awinishere awinishere commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

DEPRECATED_ANNOTATIONS is a synchronizedList, but isDeprecated(..) streams it without holding
the lock synchronizedList only synchronizes single calls. A type registered by one thread while
another generates the documentation throws ConcurrentModificationException: the 500 on
/v3/api-docs in the report. Same field also grows without bound, since SpringDocKotlinConfiguration
registers Deprecated::class.java on every context start.

Made the registry a CopyOnWriteArraySet the fix suggested in the issue, all usages add,contains, stream are Set operations, so nothing else changed.

Running the reported scenario as is context start as writer, isDeprecated as reader, JDK 21
report is on JDK 26:

3.2.0 this branch
size after 100 context starts 101 2
CME while reading concurrently 5 of 5 runs 0 of 5 runs

2 is correct: java.lang.Deprecated and kotlin.Deprecated are distinct types, only duplicates go.

Added SchemaPropertyDeprecatingConverterTest 3 tests. Two of them fail on the previous code with
expected: <1> but was: <101> and expected: <null> but was: ConcurrentModificationException; the
third asserts @Deprecated is still detected and passes on both. Full reactor: 25 modules, 1850 tests,
0 failures.

Fixes #3400

This branch has not been deployed

No deployments
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.

ConcurrentModificationException in SchemaPropertyDeprecatingConverter.isDeprecated, and DEPRECATED_ANNOTATIONS gains a duplicate on every context start

1 participant