diff --git a/README.md b/README.md index facccc9..78b59ca 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ The library has springdoc-openapi as a provided dependency, thus users of the library have to include that dependency in their projects: - for springdoc-openapi 1.x versions `1.6.7` up to `1.7.0` (including) of `"org.springdoc" % "springdoc-openapi-webmvc-core"` are supported -- for springdoc-openapi 2.x versions `2.0.0` up to `2.3.0` (including) of +- for springdoc-openapi 2.x versions `2.0.0` up to `2.8.9` (including) of `"org.springdoc" % "springdoc-openapi-starter-webmvc-api"` are supported ### Add library dependency to SBT/Maven diff --git a/examples/springdoc-openapi-scala-2/simple/build.sbt b/examples/springdoc-openapi-scala-2/simple/build.sbt index 34b64b1..35184df 100644 --- a/examples/springdoc-openapi-scala-2/simple/build.sbt +++ b/examples/springdoc-openapi-scala-2/simple/build.sbt @@ -22,7 +22,7 @@ lazy val root = (project in file(".")) .settings( libraryDependencies ++= Seq( "za.co.absa" %% "springdoc-openapi-scala-2" % `springdoc-openapi-scala-2-version`, - "org.springdoc" % "springdoc-openapi-starter-webmvc-api" % "2.3.0", + "org.springdoc" % "springdoc-openapi-starter-webmvc-api" % "2.8.9", "org.springframework.boot" % "spring-boot-starter-web" % "3.2.0", "org.playframework" %% "play-json" % "3.0.1" ), diff --git a/library/src/main/scala/za/co/absa/springdocopenapiscala/OpenAPIModelRegistration.scala b/library/src/main/scala/za/co/absa/springdocopenapiscala/OpenAPIModelRegistration.scala index ccbfb8d..17aa0ce 100644 --- a/library/src/main/scala/za/co/absa/springdocopenapiscala/OpenAPIModelRegistration.scala +++ b/library/src/main/scala/za/co/absa/springdocopenapiscala/OpenAPIModelRegistration.scala @@ -17,7 +17,7 @@ package za.co.absa.springdocopenapiscala import io.swagger.v3.oas.models.Components -import io.swagger.v3.oas.models.media.{Discriminator, Schema} +import io.swagger.v3.oas.models.media.{ArraySchema, BooleanSchema, Discriminator, IntegerSchema, NumberSchema, ObjectSchema, Schema, StringSchema, UUIDSchema} import java.time.{Instant, LocalDate, LocalDateTime, LocalTime, ZonedDateTime} import java.util.UUID @@ -27,6 +27,7 @@ import scala.reflect.runtime.universe._ import OpenAPIModelRegistration._ import java.sql.Timestamp +import scala.collection.Seq class OpenAPIModelRegistration( components: Components, @@ -69,7 +70,7 @@ class OpenAPIModelRegistration( handleType(tpe) } - private case class OpenAPISimpleType(tpe: String, format: Option[String] = None) + private case class OpenAPISimpleType(schema: Schema[_], format: Option[String] = None, _type: Option[String] = None) @tailrec private def handleType(tpe: Type): Schema[_] = { @@ -96,8 +97,7 @@ class OpenAPIModelRegistration( private def handleCaseType(tpe: Type): Schema[_] = { val name = tpe.typeSymbol.name.toString.trim - val schema = new Schema - schema.setType("object") + val schema = new ObjectSchema val fields = tpe.decls.collect { case field: TermSymbol if field.isVal => field } @@ -114,17 +114,15 @@ class OpenAPIModelRegistration( private def handleMap(keyType: Type, valueType: Type): Schema[_] = keyType match { case _ if keyType <:< typeOf[String] => - val schema = new Schema - schema.setType("object") + val schema = new ObjectSchema schema.setAdditionalProperties(handleType(valueType)) schema case _ => throw new IllegalArgumentException("In OpenAPI 3.0.x Map must have String key type.") } private def handleSeqLike(tpe: Type): Schema[_] = { - val schema = new Schema + val schema = new ArraySchema val innerSchema = handleType(tpe.typeArgs.head) - schema.setType("array") schema.setItems(innerSchema) schema } @@ -139,8 +137,7 @@ class OpenAPIModelRegistration( val enumValues = parentObjectType.members.filter(isSymbolEnumerationValue) val enumValuesAsStrings = enumValues.map(_.name.toString.trim) - val schema = new Schema[String] - schema.setType("string") + val schema = new StringSchema schema.setEnum(enumValuesAsStrings.toList.asJava) schema } @@ -224,33 +221,39 @@ class OpenAPIModelRegistration( } private def handleSimpleType(tpe: Type): Schema[_] = { - val schema = new Schema - val OpenAPISimpleType(terminalTpe, format) = getOpenAPISimpleType(tpe) - schema.setType(terminalTpe) - format.foreach(f => schema.setFormat(f)) - schema + val simpleType = getOpenAPISimpleType(tpe) + simpleType.format.foreach(simpleType.schema.setFormat) + simpleType._type.foreach(simpleType.schema.setType) + simpleType.schema } private def getOpenAPISimpleType(tpe: Type): OpenAPISimpleType = tpe.dealias match { - case t if t =:= typeOf[Byte] => OpenAPISimpleType("integer", Some("int32")) - case t if t =:= typeOf[Short] => OpenAPISimpleType("integer", Some("int32")) - case t if t =:= typeOf[Int] => OpenAPISimpleType("integer", Some("int32")) - case t if t =:= typeOf[Long] => OpenAPISimpleType("integer", Some("int64")) - case t if t =:= typeOf[Float] => OpenAPISimpleType("number", Some("float")) - case t if t =:= typeOf[Double] => OpenAPISimpleType("number", Some("double")) - case t if t =:= typeOf[Char] => OpenAPISimpleType("string") - case t if t =:= typeOf[String] => OpenAPISimpleType("string") - case t if t =:= typeOf[UUID] => OpenAPISimpleType("string", Some("uuid")) - case t if t =:= typeOf[Boolean] => OpenAPISimpleType("boolean") - case t if t =:= typeOf[Unit] => OpenAPISimpleType("null") - case t if t =:= typeOf[ZonedDateTime] => OpenAPISimpleType("string", Some("date-time")) - case t if t =:= typeOf[Instant] => OpenAPISimpleType("string", Some("date-time")) - case t if t =:= typeOf[LocalDateTime] => OpenAPISimpleType("string", Some("date-time")) - case t if t =:= typeOf[LocalDate] => OpenAPISimpleType("string", Some("date")) - case t if t =:= typeOf[LocalTime] => OpenAPISimpleType("string", Some("time")) - case t if t =:= typeOf[Timestamp] => OpenAPISimpleType("string", Some("date-time")) - case t if t =:= typeOf[BigDecimal] => OpenAPISimpleType("number") - case t if t =:= typeOf[BigInt] => OpenAPISimpleType("integer") + case t if t =:= typeOf[Byte] || t =:= typeOf[Short] || t =:= typeOf[Int] => + OpenAPISimpleType(new IntegerSchema()) + case t if t =:= typeOf[Long] => + OpenAPISimpleType(new IntegerSchema(), Some("int64")) + case t if t =:= typeOf[Float] => + OpenAPISimpleType(new NumberSchema(), Some("float")) + case t if t =:= typeOf[Double] => + OpenAPISimpleType(new NumberSchema(), Some("double")) + case t if t =:= typeOf[Char] || t =:= typeOf[String] => + OpenAPISimpleType(new StringSchema()) + case t if t =:= typeOf[UUID] => + OpenAPISimpleType(new UUIDSchema()) + case t if t =:= typeOf[Boolean] => + OpenAPISimpleType(new BooleanSchema()) + case t if t =:= typeOf[Unit] => + OpenAPISimpleType(new Schema, None, Some("null")) + case t if t =:= typeOf[ZonedDateTime] || t =:= typeOf[Instant] || t =:= typeOf[LocalDateTime] || t =:= typeOf[Timestamp] => + OpenAPISimpleType(new StringSchema(), Some("date-time")) + case t if t =:= typeOf[LocalDate] => + OpenAPISimpleType(new StringSchema(), Some("date")) + case t if t =:= typeOf[LocalTime] => + OpenAPISimpleType(new StringSchema(), Some("time")) + case t if t =:= typeOf[BigDecimal] => + OpenAPISimpleType(new NumberSchema()) + case t if t =:= typeOf[BigInt] => + OpenAPISimpleType(new IntegerSchema(), Some(null)) } private def registerAsReference(name: String, schema: Schema[_]): Schema[_] = { diff --git a/library/src/test/scala/za/co/absa/springdocopenapiscala/OpenAPIModelRegistrationSpec.scala b/library/src/test/scala/za/co/absa/springdocopenapiscala/OpenAPIModelRegistrationSpec.scala index 9ec1145..a88fb43 100644 --- a/library/src/test/scala/za/co/absa/springdocopenapiscala/OpenAPIModelRegistrationSpec.scala +++ b/library/src/test/scala/za/co/absa/springdocopenapiscala/OpenAPIModelRegistrationSpec.scala @@ -17,7 +17,7 @@ package za.co.absa.springdocopenapiscala import io.swagger.v3.oas.models.Components -import io.swagger.v3.oas.models.media.Schema +import io.swagger.v3.oas.models.media.{IntegerSchema, Schema} import org.scalatest import org.scalatest.flatspec.AnyFlatSpec @@ -281,7 +281,7 @@ class OpenAPIModelRegistrationSpec extends AnyFlatSpec { assertAdditionalPropertiesAreAsExpected( actualSchemas, "Maps.a", - (new Schema).`type`("integer").format("int32") + new IntegerSchema() ) assertTypeAndFormatAreAsExpected(actualSchemas, "Maps.b", "object") assertAdditionalPropertiesAreAsExpected( diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 79854e3..d6255cb 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -27,7 +27,7 @@ object Dependencies { def springdocOpenapi(majorVersion: Int): String = majorVersion match { case 1 => "[1.6.7,1.7.0]" - case 2 => "[2.0.0,2.3.0]" + case 2 => "[2.0.0,2.8.9]" } }