我想根据不同的类型(包括精炼的Scala)提供案例类的json模式(在编译时)
object JsonSchema {
def jsonSchema[T]: String = macro impl[T]
def impl[T: c.WeakTypeTag](c: scala.reflect.macros.whitebox.Context): c.Expr[String] = {
import c.universe._
val r = weakTypeOf[T].decls.collect {
case m: MethodSymbol if m.isCaseAccessor =>
val typeArgs = m.info match {
case NullaryMethodType(v) => v.typeArgs
}
val supportedStringFormat = List("IPv4", "IPv6", "Uri")
typeArgs match {
case _type :: _predicate :: Nil if _type =:= typeOf[String] && supportedStringFormat.contains(_predicate.typeSymbol.name.toString()) => Json.obj(m.name.decodedName.toString -> Json.obj("type" -> "string", "format" -> _predicate.typeSymbol.name.toString().toLowerCase()))
case _type :: _predicate :: Nil if _type =:= typeOf[String] && _predicate =:= typeOf[NonEmpty] => Json.obj(m.name.decodedName.toString -> Json.obj("type" -> "string", "minLength" -> 1))
case _type :: _predicate :: Nil if _type =:= typeOf[String] && _predicate =:= typeOf[Size[_0]] => {
val size = _predicate.typeArgs match {
case h :: _ if h <:< typeOf[Nat._0] => 0
}
Json.obj(m.name.decodedName.toString-> Json.obj("type" -> "string", "minLength" -> size))
}
case _type :: _ if _type =:= typeOf[String] => Json.obj(m.name.decodedName.toString -> Json.obj("type" -> "string"))
case _type :: _predicate :: Nil if _type =:= typeOf[Int] && _predicate =:= typeOf[Positive] => Json.obj(m.name.decodedName.toString ->Json.obj("type" -> "int", "minValue" -> 1))
case _type :: _predicate :: Nil if _type =:= typeOf[List[String]] && _predicate =:= typeOf[NonEmpty] => Json.obj(m.name.decodedName.toString-> Json.obj("type" -> "array", "minLength" -> 1))
case List() => Json.obj(m.name.decodedName.toString ->Json.obj("type"-> m.info.typeSymbol.name.decodedName.toString.toLowerCase()))
case other => Json.obj("other"-> other.map(_.toString()).mkString)
}
}
val json = r.reduce(_ ++ _)
c.Expr[String](q"""${json.toString()}""")
}
}
我希望能够对所有无形的自然进行模式匹配:
typeOf[Size[_]]
代替typeOf[Size[_0]]
但我有一个编译错误:
No TypeTag available for eu.timepit.refined.collection.Size[_]
[error] case _type :: _predicate :: Nil if _type =:= typeOf[String] && _predicate =:= typeOf[Size[_]] => {
我想得到一个 int 的大小
val size = _predicate.typeArgs match {
case h :: _ if h <:< typeOf[Nat._0] => 0
}
用法 :
case class StringWithMinSize22(k: String Refined MinSize[_22])
"String with min size 22" must {
"return a schema with min size" in {
JsonSchema.jsonSchema[StringWithMinSize22] mustBe """{"k":{"type":"string","minLength":22}}"""
}
}