我试图创建一个通用的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注入这个服务?
答案 0 :(得分:2)
如何为每个伴侣对象使用某种特征来要求Reads
和Writes
?
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
。这不会使隐式解决方案有效,但是一旦你有了这个引用,你就可以依靠继承来使控制器中的Reads
和Writes
可用。
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
}