使用参数类型

时间:2015-07-23 13:22:26

标签: json scala serialization playframework parameterized-types

我已经看了一眼:Scala type deferring,它看起来很接近我的问题,但不幸的是我无法用答案解决它。

所以,这是代码:

我的GenericModel

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)

就像我之前说的那样,我已经尝试过隐式写作。 感谢您的帮助,我希望我没有错过关于beggining的引用主题的内容。

3 个答案:

答案 0 :(得分:0)

想法是添加[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
}

答案 1 :(得分:0)

implicit val pushFormat = Json.format[Push]

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

解决此错误而不是使用Json.format [推送]扩展OWrites和读取

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中,将[T]写入OWrites [T]

答案 2 :(得分:0)

我有同样的问题,我必须实现一个方法来告诉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
       }
   }

...

}

希望这会有所帮助:)