斯卡拉 - 玩! 2 - Generic Crud

时间:2015-01-24 15:00:48

标签: json scala generics playframework-2.0

我试图创建一个通用的crud控制器,但我陷入了json问题。

我对每个域对象都有一个隐式读写,因为我的crud控制器是"泛型",我为它传递了T,这导致没有找到类型为T的隐式转换器

这是我的TestController

object AddressController extends Controller with CrudController[Address, AddressServiceModule] {

}

这是我的CrudController

trait CrudController[T, K <: GenericServiceModule[T]] extends Controller {

  var service: K = _

  def get(uuid: String) = Action.async {
    val future = service.genericService.getById(UUID.fromString(uuid))
    future.map {
      case Some(t) => Ok(Json.toJson(t))
      case None => NotFound
    }.recover {
      case t =>
        Logger.error("Something went wrong", t)
        InternalServerError(t.getMessage)
    }
  }
}
然后我得到了

No Json serializer found for type T.

正如我所说,我对我的地址模型进行了读写

implicit val addressReads = Json.reads[Address]
implicit val addressWrites = Json.writes[Address]

但是由于转换器在编译时得到验证,我不知道如何解决这个问题。没有机会用相同的逻辑编写10,20个crud控制器。

有什么想法吗?

更新

仅仅是为了测试,我改变了Ok(t.toString)的Ok(Json.toJson(t))然后我又遇到了另一个问题......

我服务上的NullPointer

var service: K = _

我的GenericServiceModule如下:

trait GenericServiceModule[T] {

  def genericService: GenericCommonService[T]

  /**
   * Common Services
   * @tparam T
   */
  trait GenericCommonService[T] {
    def getById(uuid: UUID): Future[Option[T]]
    def deleteById(uuid: UUID): Future[ResultSet]
    def insert(t: T): (UUID, Future[ResultSet])
    def update(uuid: UUID, t: T): (UUID, Future[ResultSet])
  }

}

我传递给AddressController的AddressServiceModule如下:

trait AddressServiceModule extends GenericServiceModule[Address] with CassandraService {

  object genericService extends GenericCommonService[Address] {

    override def getById(uuid: UUID): Future[Option[Address]] = {
      Address.select.where(_.id eqs uuid).one()
    }
}

有没有办法通过我的CrudController注入这个服务?

1 个答案:

答案 0 :(得分:2)

如何为每个伴侣对象使用某种特征来要求ReadsWrites

trait CrudObject[T] {
    val reads: Reads[T]
    val writes: Writes[T]
}

例如:

object Address extends CrudObject[Address] {
    implicit val reads: Reads[Address] = Json.reads[Address]
    implicit val writes: Writes[Address] = Json.writes[Address]

    // other code ..
}

然后在您的通用控制器中,需要引用伴随对象(由CrudObject特征标记)和GenericServiceModule。这不会使隐式解决方案有效,但是一旦你有了这个引用,你就可以依靠继承来使控制器中的ReadsWrites可用。

trait CrudController[T] extends Controller {

  def service: GenericServiceModule[T]

  def companion: CrudObject[T]

  implicit def reads: Reads[T] = companion.reads

  implicit def writes: Reads[T] = companion.writes

  def get(uuid: String) = Action.async {
    val future = service.genericService.getById(UUID.fromString(uuid))
    future.map {
      case Some(t) => Ok(Json.toJson(t))
      case None => NotFound
    }.recover {
      case t =>
        Logger.error("Something went wrong", t)
        InternalServerError(t.getMessage)
    }
  }
}

然后您的实现可能如下所示:

object AddressController extends CrudController[Address] {

   def service = AddressServiceModule

   def companion = Address

}