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.