I'm scala newbie and trying to understand it's base concepts. With use of play/scala/slick I'm trying to implement trivial app which allows user to perform CRUD operations on another users. So problem I faces is that I don't understand how I should use implicit conversions to convert model object to DTO object.
Here is what I've got so far:
Application.scala (Controller class):
//returns list of users def users = Action.async { val userList = userDAO.all() userList .map { list => Ok(list.map(elem => Json.toJson(elem))) } .recover { case _ => InternalServerError } } User.scala (model object, represents entry in database):
case class User(id: Long, login: String, password: String) extends BaseEntity UserDto.scala (DTO, object, representing User in user list):
case class UserDto(id: Long, login: String) { implicit def userWriter = Json.writes[UserDto] implicit def user2UserDto(user: User): UserDto = UserDto(user.id, user.login) } In code above, at #1 tag, I get a error which states that User can't be converted to json. Exact error message: Error:(40, 53) No Json serializer found for type Application.this.userDAO.Entity. Try to implement an implicit Writes or Format for this type. .map { list => Ok(list.map(elem => Json.toJson(elem))) }. How and where should I implement conversion from User to UserDto so that it works and not, say, ugly?
For example, in Java I would implement each Dto object with public User to() and public static UserDto from(User user) so that I can convert them. Should I do the same in scala or there is more elegant way to accomplish this task?
EDITION Edited version of users method:
def users = Action.async { val userList = userDAO.all() userList .map { list => Ok(list.map(elem => Json.toJson(elem : UserDto))) } .recover { case _ => InternalServerError } } Have the following compiler errors:
Error:(41, 24) not enough arguments for method apply: (implicit writeable: play.api.http.Writeable[Seq[play.api.libs.json.JsValue]])play.api.mvc.Result in class Status. Unspecified value parameter writeable. .map { list => Ok(list.map(elem => Json.toJson(elem : UserDto))) } Error:(41, 24) Cannot write an instance of Seq[play.api.libs.json.JsValue] to HTTP response. Try to define a Writeable[Seq[play.api.libs.json.JsValue]] .map { list => Ok(list.map(elem => Json.toJson(elem : UserDto))) } It seems that compiler doesn't see userWriter in UserDto object.
1 Answer
Don't define the implicits inside the case class. Define them in a companion object:
case class UserDto(id: Long, login: String) object UserDto { implicit def userWriter = Json.writes[UserDto] implicit def user2UserDto(user: User): UserDto = UserDto(user.id, user.login) } When you define them inside a case class, they become instance methods only available from an instance of the class. When you define them on a companion object, they are defined globally (not tied to an instance) and they are equivalent to static methods in java. From there, scala's implicit resolution mechanism can find them.
3