Repository navigation
[kotlin-spring] seal allOf discriminator parent interfaces by default - #23953
Merged
wing328 merged 1 commit intoSep 28, 2026
Conversation
This was referenced Jun 5, 2026
rvlasveld
marked this pull request as draft
June 5, 2026 11:11
rvlasveld
commented
Jun 5, 2026
rvlasveld
commented
Jun 5, 2026
This comment was marked as outdated.
This comment was marked as outdated.
rvlasveld
marked this pull request as ready for review
June 5, 2026 12:35
Contributor
Author
|
@wing328, could you help get this reviewed? |
rvlasveld
force-pushed
the
fix/kotlin-spring-seal-allof-discriminator-interfaces
branch
from
September 20, 2026 13:58
4433836 to
3618a83
Compare
Member
|
please resolve the merge conflicts when you've time and i'll try to get it merged before the upcoming stable release since the change is straightforward and users can easily fallback by setting the option to false. |
A model with a discriminator is rendered as an interface. Because the generator knows every subtype at generation time, that interface can be sealed, which lets callers use exhaustive `when` matching and stops external code from adding implementors that the discriminator mapping does not know about. Adds `useSealedDiscriminatorInterfaces` (default true). Set it to false to restore the plain `interface` rendering, which is needed when the generated interface is implemented from outside the generated package. Also declares SchemaSupportFeature.allOf, which the generator supports but did not advertise. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VBn7VWUxZL6mTUbg21xNjm
rvlasveld
force-pushed
the
fix/kotlin-spring-seal-allof-discriminator-interfaces
branch
from
September 27, 2026 21:07
3618a83 to
e89f258
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A model carrying a discriminator is rendered as an
interface. The generator knows every subtype at generation time, so that interface can be sealed:Two things this buys:
whenover the subtypes, with noelsebranch and a compile error when a new subtype appears in the spec.Pet, which matters because the discriminator mapping cannot describe a type it has never seen.Behaviour change — on by default
useSealedDiscriminatorInterfacesdefaults totrue, so this changes output for every existing user with anallOfdiscriminator, with no action on their part.The rationale for defaulting on rather than off:
oneOfdiscriminator parents are already sealed unconditionally in this generator (viaoneof_interface.mustache, untouched here). LeavingallOfparents unsealed by default would keep two polymorphism styles behaving differently for no reason a user could predict. This aligns them.The case it breaks is real but narrow — implementing the generated interface from a module outside the generated package:
This is the main decision for maintainers on this PR. If the project would rather introduce it opt-in and flip the default in a later major, changing one line (
= true→= false) plus regenerating samples is all it takes — say the word and I will push that.Scope
Only the
allOf/dataClass.mustachepath is touched.oneOfparents render through a different template and are unaffected by the flag in either position — there is an explicit regression test for that (testOneOfInterfaceStillSealedWhenAllOfFlagOff).Sealed-ness composes correctly with
x-kotlin-implementsexternal supertypes:sealed interface Pet : com.some.pack.Named.Tests
KotlinSpringServerCodegenTest: 287 passing, 4 of them new — sealed by default, plain interface on opt-out, composition with external supertypes, and theoneOf-unaffected regression test above.Samples
Regenerated all
kotlin-springsample configs. Three change — notekotlin-springboot-request-cookieis included, which the earlier revision of this PR had missed:kotlin-springboot-x-kotlin-implements—Pet.ktkotlin-springboot-include-http-request-context-delegate—Pet.ktkotlin-springboot-request-cookie—Animal.ktFor maintainers
overlap is a both-added resolution at the tail of
KotlinSpringServerCodegenTest.java.open classchange and this one edit oppositebranches of the same
dataClass.mustacheline; that is now resolved in this branch, so the linecarries both (
sealedfor the discriminator branch,openfor the non-discriminator branch).This PR therefore also seals
Animalin theallOf-multilevelsample [kotlin-spring] fix multi-level allOf inheritance (fixes #18206) #23954 added.sealed interface Animal+open class Dog : Animal+data class BigDog : Dog(...)builds cleanly — verified withgradlew compileKotlinon theregenerated sample. Worth noting because no single PR's CI exercised that combination.
truevsfalse) — see above. This is the one judgement call in the PR.docs/generators/kotlin-spring.mdmovesallOffrom✗to✓. That is a pre-existing mis-declaration (the generator has long handledallOfinheritance) and is orthogonal to sealing; it rides here only because this is the one PR of the three that regenerates the docs. Happy to split it out if you would rather keep it separate.🤖 Generated with Claude Code
https://claude.ai/code/session_01VBn7VWUxZL6mTUbg21xNjm