From 3e0056d18e2c275b8ec785850f76a68aaedd549d Mon Sep 17 00:00:00 2001 From: timofeyka Date: Mon, 30 Sep 2024 17:58:54 +0100 Subject: [PATCH 1/2] allow reference to a model from OpenApiContentProperty --- .../openapi/plugin/test/JavalinTest.java | 1 + .../openapi/plugin/test/JavalinTest.java | 1 + .../processor/generators/OpenApiGenerator.kt | 29 ++++++++++++------- .../io/javalin/openapi/OpenApiAnnotations.kt | 3 +- wiki | 2 +- 5 files changed, 23 insertions(+), 13 deletions(-) diff --git a/examples/javalin-gradle-kotlin/src/main/java/io/javalin/openapi/plugin/test/JavalinTest.java b/examples/javalin-gradle-kotlin/src/main/java/io/javalin/openapi/plugin/test/JavalinTest.java index 728b34b..a418490 100644 --- a/examples/javalin-gradle-kotlin/src/main/java/io/javalin/openapi/plugin/test/JavalinTest.java +++ b/examples/javalin-gradle-kotlin/src/main/java/io/javalin/openapi/plugin/test/JavalinTest.java @@ -203,6 +203,7 @@ public static void main(String[] args) { @OpenApiContent(mimeType = "image/png", type = "string", format = "base64"), // single file upload, @OpenApiContent(mimeType = "multipart/form-data", properties = { @OpenApiContentProperty(name = "form-element", type = "integer"), // random element in form-data + @OpenApiContentProperty(name = "reference", from = KotlinEntity.class), // reference to another object @OpenApiContentProperty(name = "file-name", isArray = true, type = "string", format = "base64") // multi-file upload }) } diff --git a/examples/javalin-maven-java/src/main/java/io/javalin/openapi/plugin/test/JavalinTest.java b/examples/javalin-maven-java/src/main/java/io/javalin/openapi/plugin/test/JavalinTest.java index e464e3d..4333929 100644 --- a/examples/javalin-maven-java/src/main/java/io/javalin/openapi/plugin/test/JavalinTest.java +++ b/examples/javalin-maven-java/src/main/java/io/javalin/openapi/plugin/test/JavalinTest.java @@ -175,6 +175,7 @@ public static void main(String[] args) { @OpenApiContent(mimeType = "image/png", type = "string", format = "base64"), // single file upload, @OpenApiContent(mimeType = "multipart/form-data", properties = { @OpenApiContentProperty(name = "form-element", type = "integer"), // random element in form-data + @OpenApiContentProperty(name = "reference", from = KotlinEntity.class) // reference to another object @OpenApiContentProperty(name = "file-name", isArray = true, type = "string", format = "base64") // multi-file upload }) } diff --git a/openapi-annotation-processor/src/main/kotlin/io/javalin/openapi/processor/generators/OpenApiGenerator.kt b/openapi-annotation-processor/src/main/kotlin/io/javalin/openapi/processor/generators/OpenApiGenerator.kt index 95b7c18..cee3770 100644 --- a/openapi-annotation-processor/src/main/kotlin/io/javalin/openapi/processor/generators/OpenApiGenerator.kt +++ b/openapi-annotation-processor/src/main/kotlin/io/javalin/openapi/processor/generators/OpenApiGenerator.kt @@ -444,22 +444,29 @@ internal class OpenApiGenerator { schema.addProperty("type", "object") for (contentProperty in properties) { - val propertyScheme = JsonObject() val propertyFormat = contentProperty.format.takeIf { it != NULL_STRING } - if (contentProperty.isArray) { - propertyScheme.addProperty("type", "array") - - val items = JsonObject() - items.addProperty("type", contentProperty.type) - propertyFormat?.let { items.addProperty("format", it) } - propertyScheme.add("items", items) + val contentPropertyFrom = contentAnnotation.getTypeMirror { contentProperty.from } + val propertyScheme = if (contentPropertyFrom.getFullName() != NULL_CLASS::class.java.name) { + createTypeDescriptionWithReferences(contentPropertyFrom) } else { - propertyScheme.addProperty("type", contentProperty.type) - propertyFormat?.let { propertyScheme.addProperty("format", it) } + JsonObject().apply { + addProperty("type", contentProperty.type) + propertyFormat?.let { addProperty("format", it) } + } } - propertiesSchema.add(contentProperty.name, propertyScheme) + propertiesSchema.add(contentProperty.name, + if (contentProperty.isArray) { + // wrap into OpenAPI array object + JsonObject().apply { + addProperty("type", "array") + add("items", propertyScheme) + } + } else { + propertyScheme + } + ) } schema.add("properties", propertiesSchema) diff --git a/openapi-specification/src/main/kotlin/io/javalin/openapi/OpenApiAnnotations.kt b/openapi-specification/src/main/kotlin/io/javalin/openapi/OpenApiAnnotations.kt index e23767e..87c31ab 100644 --- a/openapi-specification/src/main/kotlin/io/javalin/openapi/OpenApiAnnotations.kt +++ b/openapi-specification/src/main/kotlin/io/javalin/openapi/OpenApiAnnotations.kt @@ -147,9 +147,10 @@ annotation class OpenApiContent( @Target() @Retention(RUNTIME) annotation class OpenApiContentProperty( + val from: KClass<*> = NULL_CLASS::class, val name: String, val isArray: Boolean = false, - val type: String, + val type: String = NULL_STRING, val format: String = NULL_STRING ) diff --git a/wiki b/wiki index bffdf4c..204546a 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit bffdf4c38ce5607055c1b9979762602b7b746a6f +Subproject commit 204546a351da302ada6fb49f74fc7a41f1a63337 From 2536d07d7466efad723e1b0c9aa358dc65e3831e Mon Sep 17 00:00:00 2001 From: timofeyka Date: Tue, 1 Oct 2024 11:20:03 +0100 Subject: [PATCH 2/2] add test for recursive class --- .../openapi/processor/TypeMappersTest.kt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/openapi-annotation-processor/src/test/kotlin/io/javalin/openapi/processor/TypeMappersTest.kt b/openapi-annotation-processor/src/test/kotlin/io/javalin/openapi/processor/TypeMappersTest.kt index b0f358a..1911ab4 100644 --- a/openapi-annotation-processor/src/test/kotlin/io/javalin/openapi/processor/TypeMappersTest.kt +++ b/openapi-annotation-processor/src/test/kotlin/io/javalin/openapi/processor/TypeMappersTest.kt @@ -197,4 +197,21 @@ internal class TypeMappersTest : OpenApiAnnotationProcessorSpecification() { )) } -} \ No newline at end of file + private class Loop( + val self: Loop?, + ) + + + @OpenApi( + path = "recursive", + versions = ["should_map_recursive_type"], + responses = [OpenApiResponse(status = "200", content = [OpenApiContent(from = Loop::class)])] + ) + @Test + fun should_map_recursive_type() = withOpenApi("should_map_recursive_type") { + assertThatJson(it) + .inPath("$.components.schemas.Loop.properties.self") + .isObject + .containsEntry("\$ref", "#/components/schemas/Loop") + } +}