Skip to content

Schema annotation not working in Kotlin super class (has workaround) #3010

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
janjouketjalsma opened this issue May 27, 2025 · 3 comments
Open

Comments

@janjouketjalsma
Copy link

janjouketjalsma commented May 27, 2025

Describe the bug
When using Kotlin, annotating a field with @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED) does not work on the super class. It does however work on the "main" entity. This inconsistency could be addressed.

To Reproduce
Steps to reproduce the behavior:

  • What version of spring-boot you are using? 3.5
  • What modules and versions of springdoc-openapi are you using? 2.8.8
  • What is the actual and the expected result using OpenAPI Description (yml or json)?
    Actual:
"required": [
          "bar"
          "id"
        ]

Expected:

"required": [
          "id"
        ]
  • Provide with a sample code (HelloController) or Test that reproduces the problem
// Any controller doing POST using inheritance in Kotlin. Example:

@MappedSuperclass
class AbstractEntity(
	@Column(name = "created_at")
	@Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED) // <-- ignored
	val bar: String = "barString",
)

@Entity
class ConcreteEntity(
	@Id
	var id: Long = 1,

	@Column(name = "updated_at")
	@Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED) // <-- works
	val foo: String = "fooString",
): AbstractEntity()

Expected behavior

  • Fields annotated with @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED) are not required in the generated OpenApi spec.

Workaround:
Add get: before the annotation in the super class to make the annotation explicitly attached to the getter. @get:Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED)

@mymx2
Copy link

mymx2 commented May 28, 2025

  • Annotation use-site targets
    When you're annotating a property or a primary constructor parameter, there are multiple Java elements which are generated from the corresponding Kotlin element, and therefore multiple possible locations for the annotation in the generated Java bytecode. To specify how exactly the annotation should be generated, use the following syntax:

Image

just @Schema:

Image

Image

with @field:

Image

Image

@janjouketjalsma
Copy link
Author

janjouketjalsma commented May 28, 2025

Hi @mymx2 thanks for the screenshots. I'm aware of these use-site targets. This was the workaround mentioned in my original post and indeed fixes the issue.

The interesting thing is that the annotation works without explicit use-site target in the subclass, but not in the superclass.
I think this inconsistency is something that could be addressed, to avoid unexpected results when super classes are being used. What do you think?

@Mattias-Sehlstedt
Copy link

Class introspection comes from swagger-core. You can play around with how they introspect a class by using

ResolvedSchema resolvedSchema = ModelConverters.getInstance(true)
                .resolveAsResolvedSchema(
                        new AnnotatedType(YourClazz.class).resolveAsRef(false));

I discuss my experiences regarding the introspection here (I have not myself found any resource that describes exactly how it is done and why).

So my understanding is that if you feel like this is a behavior that should exist, then it is something that you will have to raise and discuss with the maintainers of swagger-core.

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

No branches or pull requests

3 participants