jsonschema-generator
jsonschema-generator copied to clipboard
Support Kotlin annotations
It seems that the Jackson module ignores Jackson annotations in my Kotlin code, e.g.:
data class TestNamedProperty( @JsonProperty("my_text") val text: String)
The generator generates a schema with the property name text
instead of my_text
. I traced the generation with a debugger, and it seems that the method getPropertyNameOverrideBasedOnJsonPropertyAnnotation
in the Jackson module does not see the annotation in the Java class that I created from Kotlin using TestNamedProperty::class.java
.
I suspect that it has to do with how Kotlin and Java annotations differ - https://stackoverflow.com/questions/72559287/how-to-read-kotlin-annotation
I guess that means that jsonschema-generator
cannot be used from Kotlin, which is a bummer for my use case :(
It looks like I jumped to a conclusion too quickly as this doesn't seem to be a general problem with Kotlin annotations, as I was able to successfully create a correct schema for a Kotline class like so:
class TestNamedProperty2 {
@JsonProperty("my_text")
val text: String = ""
}
So it seems that the issue is specific to Kotlin data classes. I am writing a schema generator that uses jsonschema-generator
and adds a bit of logic and configurations. Many of its (internal) users use data class so that is a hard requirement. Is this something that I can help fix? any pointers for how to approach this?
Another relevant reference: https://stackoverflow.com/questions/64118808/java-annotation-cannot-be-found-per-reflection-on-a-kotlin-data-class
Hi @moranlefler,
It's very unfortunate that the annotation goes to the constructor parameter in this scenario. Currently, those are not taken into account, but they apparently would have to in order to handle data classes correctly.
As starting point, you can extend the JacksonModule
and override its getPropertyNameOverrideBasedOnJsonPropertyAnnotation()
method (that's why it has protected
visibility 😉) to check the constructor parameters as well.
https://github.com/victools/jsonschema-generator/blob/5965fddcd0877a4a07118844dd258d8a12f69dcd/jsonschema-module-jackson/src/main/java/com/github/victools/jsonschema/module/jackson/JacksonModule.java#L194
Preferably, the handling would be generic enough to allow being included via a PR. Looking forward to your feedback there. 😃
Created a PR for this. Feedback welcomed! https://github.com/victools/jsonschema-generator/pull/359
@moranlefler
Have you tried adding @get
to the annotation?
Like this:
class TestNamedProperty2 {
@get:JsonProperty("my_text")
val text: String = ""
}
I stumbled upon the same issue using swagger 2 annotations and that did the job.
If this is indeed setting the annotations on the getter methods instead of the constructor, that'd be awesome as no change would be required here.
I'd merely include this in the documentation then, to share this with other Kotlin users. Relevant Kotlin documentation would be this then: https://kotlinlang.org/docs/annotations.html#annotation-use-site-targets
Thanks for sharing!
This is indeed setting the annotations on getter methods as shown by the output of javap
.
private data class MyParams(
@get:Schema(title="Jinja input", description = "Whole document if left empty, otherwise 'metadata.input' syntax accepted", defaultValue = " ")
val input: String = "",
)
javap -v -classpath build/classes/kotlin/test org.bfreuden.MyParams
public final java.lang.String getInput();
descriptor: ()Ljava/lang/String;
flags: (0x0011) ACC_PUBLIC, ACC_FINAL
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #29 // Field input:Ljava/lang/String;
4: areturn
LineNumberTable:
line 26: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lorg.bfreuden/MyParams;
RuntimeVisibleAnnotations:
0: #43(#44=s#51,#48=s#52,#53=s#54)
io.swagger.v3.oas.annotations.media.Schema(
title="Jinja input"
description="Whole document if left empty, otherwise \'metadata.input\' syntax accepted"
defaultValue=" "
)
RuntimeInvisibleAnnotations:
0: #11()
org.jetbrains.annotations.NotNull
I too would love to see this available in kotlin.
What I have found is by adding a @get:JsonProperty or @field:JsonProperty to you data class properties fixes the issue, however what about the kotlin classes that are out of your control.
This also has a general problem with kotlin data classes, as the @Min from jakarta.validation-api also cannot work effectively. @get:Min works and hence the problem is a kotlin issue, not that kotlin is going to fix it.
Possible work around... Suggest a new module specifically for kotlin data classes. Might consider using the kotlin reflection instead of java reflection (eg. <Type>::class instead of <Type>::class.java) to gather the information.
however what about the kotlin classes that are out of your control.
@SquirrelGrip I'm not sure I'm getting your point: if a Java class is out of your control then you cannot add annotations (min, JsonProperty) to it in order to tweak the behavior of the json schema generation, right? So why would it be required for Kotlin?
In my understanding there is no issue with Kotlin and no issue with jsonschema-generator (and this ticket should be closed :)).