【问题标题】:Scala Play 2.4 Serialize with Parameter TypeScala Play 2.4 带参数类型的序列化
【发布时间】:2015-10-13 20:03:14
【问题描述】:

我已经看过了:Scala type deferring,它看起来很接近我的问题,但很遗憾,我无法用答案解决它。

所以,这里是代码:

我的通用模型

abstract class GenericModel[T] {
  val _id: Option[BSONObjectID]
  def withId(newId: BSONObjectID): T
}

我的实现模型

case class Push
(_id: Option[BSONObjectID], text: String)
extends GenericModel[Push]
{
  override def withId(newId: BSONObjectID) = this.copy(_id = Some(newId))
}

object Push{
  implicit val pushFormat = Json.format[Push]
}

我的 DAO,使用案例类

trait GenericDao[T <: GenericModel[T]] {

  val db: DB
  val collectionName: String

  /**
   * Inserts new object
   * @param newobject
   * @return Some(stringified bsonID) or None if error
   */
  def insert(newobject: T)(implicit tjs: Writes[T]): Future[Option[BSONObjectID]] = {
    val bsonId = BSONObjectID.generate
    val beaconWithId = newobject.withId(bsonId)
    db.collection[JSONCollection](collectionName).insert(beaconWithId).map{ lastError =>
      if(lastError.ok)
        Some(bsonId)
      else
        None
    }
  }
}

我收到了错误

No Json serializer as JsObject found for type T. Try to implement an implicit OWrites or OFormat for this type

这里,在插入方法中

db.collection[JSONCollection](collectionName).insert(beaconWithId)

就像我之前说的,我已经尝试过隐式写入。 感谢您的帮助,我希望我没有错过关于开始时引用的主题的任何内容。

【问题讨论】:

  • 我实际上面临着几乎相同的问题..你已经弄清楚了吗?
  • 没有找到解决办法。我的插入方法现在在实现 DAO 中,而不是在通用 DAO 中,不幸的是,就像我搜索的那样......对不起

标签: json scala serialization playframework parameterized-types


【解决方案1】:

我遇到了同样的问题,我必须实现一个方法来告诉 Object 如何成为 JsValue:

def toJs[T : Writes](o: T) = Json.toJson(o).as[JsObject]

所以我的 MongoRepository 的插入部分看起来像这样:

trait MongoRepository[T <: MongoModel] {

lazy val db: DB = {
    import scala.concurrent.ExecutionContext.Implicits.global
    import reactivemongo.core.nodeset.Authenticate
    import scala.collection.JavaConversions._

    val driver = new MongoDriver
    val connection = driver.connection(
      config.getStringList("mongodb.servers"),
      MongoConnectionOptions(),
      Seq(Authenticate(
        config.getString("mongodb.db"),
        config.getString("mongodb.credentials.username"),
        config.getString("mongodb.credentials.password")
      )
      )
    )
    connection.db(config.getString("mongodb.db"))
  }

  def collectionName: String    
  def collection = db(collectionName)
  def ensureIndexes: Future[List[Boolean]]

  def toJs[T : Writes](o: T) = Json.toJson(o).as[JsObject]

  def insert(document: T)(implicit writer: Writes[T]): Future[Either[ServiceException, T]] = {
       document._id match {
         case None => document._id = Some(BSONObjectID.generate)
         case Some(exist) => {}
       }
       document.created = Some(DateTime.now)
       document.updated = Some(DateTime.now)
       Logger.debug(s"Inserting document: [collection=$collectionName, data=$document]")
       recoverOperation(collection.insert(toJs(document))) {
         document
       }
   }

...

}

希望这会有所帮助:)

【讨论】:

    【解决方案2】:
    implicit val pushFormat = Json.format[Push]
    

    Json.format 扩展了 Format[A] 特征,而后者又扩展了 Writes[A] 和 Reads[A]。所以错误是正确的,编译器找不到用于序列化对象的 OWrites。

    为了解决这个错误而不是使用 Json.format[Push] 扩展 OWrites 和 Reads

    implicit object Push extends OWrites[Push] {
        def writes(push: Push): JsObject = Json.obj(
          "_id" -> push.id,
          "text" -> push.text  
        }
    implicit object pushReads extends Reads[Push] {
        def reads(json: JsValue): JsResult[Push] = json match {
            case obj: JsObject => try {
                val id = (obj \ "_id").asOpt[String]
                val text = (obj \ "text").as[String] 
                JsSuccess(Push(id, text))
            } catch {
              case cause: Throwable => JsError(cause.getMessage)
            }
             case _ => JsError("expected.jsobject")
            }
    }
    

    并且在 DAO 中将 Writes[T] 更改为 OWrites[T]

    【讨论】:

      【解决方案3】:

      想法是添加[T : Writes],问题是在哪里。 你可以试试这个:

      trait GenericDao[T <: GenericModel[T]] {
      
        val db: DB
        val collectionName: String
      
        /**
         * Inserts new object
         * @param newobject
         * @return Some(stringified bsonID) or None if error
         */
        def insert[T : Writes](newobject: T)(implicit tjs: Writes[T]): Future[Option[BSONObjectID]] = {
          val bsonId = BSONObjectID.generate
          val beaconWithId = newobject.withId(bsonId)
          db.collection[JSONCollection](collectionName).insert(beaconWithId).map{ lastError =>
            if(lastError.ok)
              Some(bsonId)
            else
              None
          }
        }
      }
      

      或者这个(或两者):

      abstract class GenericModel[T : Writes] {
        val _id: Option[BSONObjectID]
        def withId(newId: BSONObjectID): T
      }
      

      【讨论】:

      • 无效。总是同样的错误。如果我在 GenericModel 中修改 T,则 Push crash on format ...
      猜你喜欢
      • 1970-01-01
      • 2016-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-15
      • 2011-02-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多