Scala Convert Model Object to Dto

Scala Convert Model Object to Dto

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.

2

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Marcus Vance
Author

Marcus Vance

Marcus Vance is a cybersecurity auditor and technology writer dedicated to educating the public about online safety, data privacy regulations, enterprise security, and emerging cyber threats.