ScalaJson隐式写,找到:任何必需的:play.api.libs.json.Json.JsValueWrapper

时间:2016-04-09 18:29:26

标签: json scala playframework

我正在使用Scala / Play Framework和Reactive Mongo构建一个Web应用程序,我希望在数据库中定义模型,而不是让它们硬编码。 为此,我正在编写一个使用FieldInstance序列的类EntityInstance:

case class EntityInstance(fields: Seq[FieldInstance])

我正在尝试接受来自任何类型的字段并将它们转换为Json:example

new FieldInstance("name", "John") | json: { "name": "John" }
new FieldInstance("age", 18) | json: { "age": 18 }

目前我正在尝试接受字符串,布尔值和整数,如果不支持该类型,我会写一些错误:

new FieldInstance("profilePicture", new Picture("john.jpg") | json: { "profilePicture": "Unsupported type 

我写了一个FieldInstance类,将fieldName作为String,将值作为任何类型。一旦该类被实例化,我就将值转换为已知类型或描述错误的String。

class FieldInstance(fieldNamec: String, valuec: Any) {
  val fieldName = fieldNamec
  val value = valuec match {
    case v: Int => v
    case v: String => v
    case v: Boolean => v
    case _ => "Unrecognized type"
  }
}
object FieldInstance {
  implicit val fieldInstanceWrites = new Writes[FieldInstance] {
    def writes(fieldInstance: FieldInstance) = Json.obj(
      fieldInstance.fieldName -> fieldInstance.value
    )
  }
}

我创建了一个带有隐式写入json的伴随对象,因此我可以在FieldInstance的实例上调用“Json.toJson()”并获取json,如上面的示例所述。

我收到错误:found: Any required: play.api.libs.json.Json.JsValueWrapper 我知道它来自于我的值是Any类型的事实,但我认为演员会将Any更改为String ||布尔||在击中作家之前的Int。

PS:忽略类的错误命名,我无法命名EntityInstance和FieldInstance,Entity和Field,因为这些是我用来描述模型的类。

2 个答案:

答案 0 :(得分:0)

我找到了解决问题的方法: 我在类中进行的类型匹配应该在隐式Write!

中完成
class FieldInstance(fieldNamec: String, valuec: Any) {
  val fieldName = fieldNamec
  val value = valuec
  override def toString(): String = "(" + fieldName + "," + value + ")";
}
object FieldInstance {
  implicit val fieldInstanceWrites = new Writes[FieldInstance] {
    def writes(fieldInstance: FieldInstance) =
      fieldInstance.value match {
        case v: Int => Json.obj(fieldInstance.fieldName -> v.asInstanceOf[Int])
        case v: String => Json.obj(fieldInstance.fieldName -> v.asInstanceOf[String])
        case v: Boolean => Json.obj(fieldInstance.fieldName -> v.asInstanceOf[Boolean])
        case _ => Json.obj(fieldInstance.fieldName -> "Unsupported type")
      }
  }
}

此代码现在允许用户使用任何类型的字段创建EntityInstance:

val ei = new EntityInstance(Seq[FieldInstance](new FieldInstance("name", "George"), new FieldInstance("age", 25), new FieldInstance("married", true)))

println("-- TEST ENTITY INSTANCE TO JSON --")
println(Json.toJson(ei))

打印:{"entity":[{"name":"George"},{"age":25},{"married":true}]}

如果您要测试它,请参阅我的EntityInstance代码:

case class EntityInstance(fields: Seq[FieldInstance])
object EntityInstance {
  implicit val EntityInstanceWrites = new Writes[EntityInstance] {
    def writes(entityInstance: EntityInstance) =
      Json.obj("entity" -> entityInstance.fields)
  }
}

答案 1 :(得分:-1)

返回String,Int或Boolean但Json.obj期望类型的值参数(String, JsValueWrapper

def obj(fields: (String, JsValueWrapper)*): JsObject = JsObject(fields.map(f => (f._1, f._2.asInstanceOf[JsValueWrapperImpl].field)))

快速修复可以将匹配的值v转换为toJson,前提是类型T的隐式Writes [T]可用(它们用于String,Int和Boolean)

class FieldInstance(fieldNamec: String, valuec: Any) {
  val fieldName = fieldNamec
  val value = valuec match {
    case v: Int => Json.toJson(v)
    case v: String => Json.toJson(v)
    case v: Boolean => Json.toJson(v)
    case _ => Json.toJson("Unrecognized type")
  }
}

如果您想查看哪些DefaultWrit可用,可以在play.api.libs.json

中的trait DefaultWrites包中浏览它们

例如:

  /**
   * Serializer for Boolean types.
   */
  implicit object BooleanWrites extends Writes[Boolean] {
    def writes(o: Boolean) = JsBoolean(o)
  }