diff --git a/src/main/scala-2/com/github/swagger/scala/converter/ErasureHelper.scala b/src/main/scala-2/com/github/swagger/scala/converter/ErasureHelper.scala index 2e76f9dd..01733e42 100644 --- a/src/main/scala-2/com/github/swagger/scala/converter/ErasureHelper.scala +++ b/src/main/scala-2/com/github/swagger/scala/converter/ErasureHelper.scala @@ -1,16 +1,26 @@ package com.github.swagger.scala.converter +import scala.reflect.runtime.universe.TermName + object ErasureHelper { def erasedOptionalPrimitives(cls: Class[_]): Map[String, Class[_]] = { import scala.reflect.runtime.universe val mirror = universe.runtimeMirror(cls.getClassLoader) - val sym = mirror.staticClass(cls.getName) - val properties = sym.selfType.members - .filterNot(_.isMethod) - .filterNot(_.isClass) - properties.flatMap { prop => + val moduleSymbol = mirror.moduleSymbol(Class.forName(cls.getName)) + val ConstructorName = "apply" + val companion: universe.Symbol = moduleSymbol.typeSignature.member(TermName(ConstructorName)) + val properties = if (companion.fullName.endsWith(ConstructorName)) { + companion.asMethod.paramLists.flatten + } else { + val sym = mirror.staticClass(cls.getName) + sym.selfType.members + .filterNot(_.isMethod) + .filterNot(_.isClass) + } + + properties.flatMap { prop: universe.Symbol => val maybeClass: Option[Class[_]] = prop.typeSignature.typeArgs.headOption.flatMap { signature => if (signature.typeSymbol.isClass) { Option(mirror.runtimeClass(signature.typeSymbol.asClass)) diff --git a/src/test/scala/com/github/swagger/scala/converter/ModelPropertyParserTest.scala b/src/test/scala/com/github/swagger/scala/converter/ModelPropertyParserTest.scala index 84afaf44..56fad8df 100644 --- a/src/test/scala/com/github/swagger/scala/converter/ModelPropertyParserTest.scala +++ b/src/test/scala/com/github/swagger/scala/converter/ModelPropertyParserTest.scala @@ -3,6 +3,7 @@ package com.github.swagger.scala.converter import io.swagger.v3.core.converter._ import io.swagger.v3.core.util.Json import io.swagger.v3.oas.models.media._ +import models.NestingObject.NestedModelWOptionInt import models._ import org.scalatest.OptionValues import org.scalatest.flatspec.AnyFlatSpec @@ -117,6 +118,41 @@ class ModelPropertyParserTest extends AnyFlatSpec with Matchers with OptionValue nullSafeList(model.value.getRequired) shouldBe empty } + it should "process Model with nested Scala Option Int" in { + val converter = ModelConverters.getInstance() + val schemas = converter.readAll(classOf[NestedModelWOptionInt]).asScala.toMap + val model = schemas.get("NestedModelWOptionInt") + model should be(defined) + model.value.getProperties should not be (null) + val optInt = model.value.getProperties().get("optInt") + optInt should not be (null) + if (RuntimeUtil.isScala3()) { + optInt shouldBe a[ObjectSchema] + } else { + optInt shouldBe a[IntegerSchema] + optInt.asInstanceOf[IntegerSchema].getFormat shouldEqual "int32" + } + nullSafeList(model.value.getRequired) shouldBe empty + } + + it should "process Model with nested Scala Option Int with Schema Override" in { + val converter = ModelConverters.getInstance() + val schemas = converter.readAll(classOf[ModelWOptionIntSchemaOverride]).asScala.toMap + val model = schemas.get("ModelWOptionIntSchemaOverride") + model should be(defined) + model.value.getProperties should not be (null) + val optInt = model.value.getProperties().get("optInt") + optInt should not be (null) + if (RuntimeUtil.isScala3()) { + optInt shouldBe a[ObjectSchema] + } else { + optInt shouldBe a[IntegerSchema] + optInt.asInstanceOf[IntegerSchema].getFormat shouldEqual "int32" + } + optInt.getDescription shouldBe "This is an optional int" + nullSafeList(model.value.getRequired) shouldBe empty + } + it should "process Model with Scala Option Int with Schema Override" in { val converter = ModelConverters.getInstance() val schemas = converter.readAll(classOf[ModelWOptionIntSchemaOverride]).asScala.toMap diff --git a/src/test/scala/models/ModelWOptionInt.scala b/src/test/scala/models/ModelWOptionInt.scala index 58702c4f..ee3a6c01 100644 --- a/src/test/scala/models/ModelWOptionInt.scala +++ b/src/test/scala/models/ModelWOptionInt.scala @@ -4,6 +4,11 @@ import io.swagger.v3.oas.annotations.media.Schema case class ModelWOptionInt(optInt: Option[Int]) +object NestingObject { + case class NestedModelWOptionInt(optInt: Option[Int]) + case class NestedModelWOptionIntSchemaOverride(@Schema(description = "This is an optional int") optInt: Option[Int]) +} + case class ModelWOptionIntSchemaOverride(@Schema(description = "This is an optional int") optInt: Option[Int]) case class ModelWOptionIntSchemaOverrideForRequired(@Schema(required = true) optInt: Option[Int])