scala playframework json implicit case class conve

2019-08-06 19:31发布

问题:

I am developing my first Play 2.1 application in Scala. The task I am trying to accomplish is to parse json into 3 different case classes. The problem is - I do not know where to declare all case classes. Each class in it's own file or all in one file. Here is what I've done (it doesn't work, case values are not visible in controller object):

  1. File LoginBase.scala

    package models
    
    
    abstract class LoginBase 
    
    case class Login(email: String, password: String) extends         LoginBase
    case class RestoreLogin(email: String, captchaID: String,         captchaAnswer: String) extends LoginBase
    case class RegisterLogin(email: String, password: String,         captchaID: String, captchaAnswer: String) extends LoginBase
    
  2. File

    package controllers
    
    import play.api._
    import play.api.mvc._
    import play.api.data._
    import play.api.data.Forms._
    import play.api.Play.current
    import play.api.cache.Cache
    import play.api.libs.json._
    import play.api.mvc._
    import play.api.libs.functional.syntax._
    
    import nl.captcha.Captcha
    import nl.captcha.Captcha._
    import nl.captcha.gimpy.FishEyeGimpyRenderer
    import nl.captcha.text.renderer.ColoredEdgesWordRenderer
    import nl.captcha.text.renderer.DefaultWordRenderer
    import nl.captcha.gimpy.DropShadowGimpyRenderer
    
    import java.io.ByteArrayOutputStream
    import javax.imageio.ImageIO
    import java.util.UUID
    
    import play.api.libs.functional.syntax._
    import models.LoginBase
    
    object LoginActions extends Controller {
    
    
        implicit val loginReads = (
          (__ \ "email").read[String] and
          (__ \ "password").read[String]
        )(Login.apply _) 
    
    
        implicit val restoreLoginReads = (
          (__ \ "email").read[String] and
          (__ \ "captchaID").read[String] and
          (__ \ "captchaAnswer").read[String]
        )(RestoreLogin) 
    
        implicit val registerLoginReads = (
          (__ \ "email").read[String] and
          (__ \ "password").read[String] and
          (__ \ "captchaID").read[String] and
          (__ \ "captchaAnswer").read[String]
        )(RegisterLogin) 
    
    
    
        def registerLogin = Action(parse.json){
            /*  To be implementd */
        }
    
    }
    

If someone can help me with this, I'll appreciate. All I can find is REPL examples, but I am missing some fundamental stuff - where to put all the pieces of code? what is the file structure?

Thanks, Andrei.

回答1:

Having multiple classes and objects inside a single file is considered good form in Scala, as long as the classes are tightly related.

please refer Elements of Scala Style? for more detail answer.

Here is example of converting json to scala case class in restful ws.

enter code here

import play.api.libs.json.{Reads, JsError, Json}
import play.api.libs.json.JsValue

object someController e

xtends Controller{

case class SomeResource(val Id:String, val someType:String, val Serialno:String)

implicit val reads:Reads[SomeResource] = Json.reads[SomeResource]

/**
   * save some object
   */
  def someService = Action(parse.json){request=>
    unmarshalOrderResource(request, (resource: SomeResource) => {
            val someValue = SomeResource(resource.Id,
                            resource.someType,resource.Serialno);
            someservice.save(someValue);
            Created(someValue.Id)
        })
  }


// method
 private def unmarshalOrderResource(request: Request[JsValue],
                                      block: (SomeResource) => Result): Result = {
        request.body.validate[SomeResource].fold(
            valid = block,
            invalid = (e => {
                val error = e.mkString
                Logger.error(error)
                BadRequest(error)
            })
        )
    }

}


回答2:

One of the things that is different between Java and Scala is that Scala requires no specific file/folder structure. The packages don't even have to correspond to folders. Also, you can have multiple classes per file.

Basically, what you have is fine.

The thing that must remain the same is the imports. So, if you're asking why your stuff won't compile, try importing everything in the models package.

import models._