Open pajooh opened 10 years ago
I'm having similar problem with a field that is a scala enumeration
for example:
object something extends Enumeration {
type EnumeratedType = Value
val aValue, anotherValue = Value
}
case class DataWithEnum(field: something.EnumeratedType)
apiOperation[DataWithEnum]("getData")
Enumerations are not supported
Ok, but as json4s supports them rather nicely it would be nice to have some way to circumvent this problem by for example having swagger see them as strings or ints (depending on serialization).
I mean that is there anyway to register just that one field of a model to be string and the rest come normally from the class. wihtou having to build the whole class model manually
JSON4S supports enumerations just fine. Whats the problem here?
Json4s only supports enumerations out of dumb luck more or less. If you have 2 Enum Values that are the same string it can't differentiate.
The problem is that the type Value
of an enumeration is defined on the Enumeration type so we really have no idea which enum we're dealing with at runtime.
Is there a plan how to fix it or just will never be supported?
Given the understandable limitation of Enumeration objects, is there any way we can pass extra info to Swagger to overcome this situation and get the attribute exposed as a string at the very least?
yes there is. You can use a model definition direclty and register it.
For example for this scalabuff generated enumeration (which in itself is already nicer than the default scala one)
object ComponentType extends net.sandrogrzicic.scalabuff.Enum {
sealed trait EnumVal extends Value
val _UNINITIALIZED = new EnumVal { val name = "UNINITIALIZED ENUM VALUE"; val id = -1 }
val SERVICE = new EnumVal { val name = "SERVICE"; val id = 0 }
val TASK = new EnumVal { val name = "TASK"; val id = 1 }
val CRON = new EnumVal { val name = "CRON"; val id = 2 }
val SPARK_JOB = new EnumVal { val name = "SPARK_JOB"; val id = 3 }
val SERVICE_VALUE = 0
val TASK_VALUE = 1
val CRON_VALUE = 2
val SPARK_JOB_VALUE = 3
def valueOf(id: Int) = id match {
case 0 => SERVICE
case 1 => TASK
case 2 => CRON
case 3 => SPARK_JOB
case _default => throw new net.sandrogrzicic.scalabuff.UnknownEnumException(_default)
}
val internalGetValueMap = new com.google.protobuf.Internal.EnumLiteMap[EnumVal] {
def findValueByNumber(id: Int): EnumVal = valueOf(id)
}
}
I have this json serializer:
class ComponentTypeSerializer extends CustomSerializer[CT.EnumVal]({ implicit fmts =>({
case JString(s) if s.toUpperCase(Locale.ENGLISH) == CT.SERVICE.name => CT.SERVICE
case JString(s) if s.toUpperCase(Locale.ENGLISH) == CT.TASK.name => CT.TASK
case JString(s) if s.toUpperCase(Locale.ENGLISH) == CT.CRON.name => CT.CRON
case JString(s) if s.toUpperCase(Locale.ENGLISH) == CT.SPARK_JOB.name => CT.SPARK_JOB
},{
case b: AD.EnumVal => JString(b.name)
})})
And I use it in a model like this:
import protocol.{ComponentType => CT}
val applicationComponent = Model(
id = "App",
name = "App",
qualifiedName = Some("protocol.App"),
description = Some("A single executable component of a service"),
properties = List(
"name" -> ModelProperty(
`type` = DataType.String,
position = 0,
required = true,
description = Some("The name of this individual component")),
"componentType" -> ModelProperty(
`type` = DataType.String,
position = 13,
required = true,
description = Some("The type of this component"),
allowableValues = AllowableValues(CT.SERVICE.name, CT.TASK.name, CT.SPARK_JOB.name, CT.CRON.name))
)
)
And in the scalatra servlet I've registered the model:
class MyServlet extends ScalatraServlet with SwaggerSupport {
registerModel(applicationComponent)
}
it's not that this won't be solved but it won't be solved in the 2.3 series. In 2.4 we're going to start using macros for more and more things to work around many of the rough edges we still have. This being one of them.
I have created a small project using macros to generate the Swagger model. It's still missing some types like Map for instance, but it can handle primitives, complex types, Scala enumerations, and Iterables. I wish this could help you guys in 2.4 to approach this problem.
You can find the code at https://github.com/crypticmind/scala-swagger-modelgen
Swagger is undergoing a big overhaul, so the spec will change. But YES thank you very much. I'll pull this in, when I get round to upgrading the swagger support in scalatra for 2.4
any idea when it would be fixed?
Still an issue in 2.4.1. Will work-around by building a custom model, which will need to be manually kept in sync when I change the case classes it maps. But of a pain though because it's a deeply nested model.
based on official guide i added swagger to my project. in swagger annotation, i have something like
which Book is database connection object from scala-activerecord:
i get java.lang.NullPointerException error arroung my apiOperation definitin. also, upgrading to latest scalatra 2.3.0-M1 with latest swagger can not help, here is my error log: