Spray parameter conversion

Source: Internet
Author: User

Recently, I used spray to do something. At the beginning, I started to get started with the doc. the most flexible way is to count its routing-DSL. Of course, due to Scala's powerful features, many different from Java, the source code looks quite laborious, especially for beginners who haven't used Scala for a long time.

The problem today is how to convert a parameter to the desired type, for example? Age = 25 & birth = 1988-01-23, can receive the int and date parameters. Soon I found the method in the document, as shown in the following code:


case class Color(red: Int, green: Int, blue: Int)val route =  path("color") {    parameters(‘red.as[Int], ‘green.as[Int], ‘blue.as[Int]) { (red, green, blue) =>      val color = Color(red, green, blue)      doSomethingWith(color) // route working with the Color instance    }  }

However, when I write it myself, I find that writing the date will cause a compilation error,


val route: Route =    path("stat" / Rest) { path =>      parameters(‘age.as[Int], ‘birth.as[java.util.Date]) { (age, birth) =>        get {          complete {            path + age.toString + birth          }        }      }    }



[info] Compiling 1 Scala source to D:\study\spray-template\target\scala-2.11\classes...[error] D:\study\spray-template\src\main\scala\com\example\MyService.scala:60: too many arguments for method parameters: (pdm: spray.routing.directives.ParamDefMagnet)pdm.Out[error]       parameters(‘age.as[Int], ‘birth.as[java.util.Date]) { (age, birth) =>[error]                 ^



I don't know what to say about the error. The classic method did not find a satisfactory answer when I googled the error message. Then I started to think about it myself. Spray or Scala has no reason to be so powerful that you can write a Type A and as [a] to convert string, there must be something magic happening behind the scenes.


So Ctrl + B (idea shortcut key, I don't want to switch back to eclipse after idea is used, this is not an advertisement). After clicking it, I found it was a case class namereceptacle, it is not the directly returned type A as I imagined. Continue to view parameters. After clicking it, it will be:


def parameters(pdm: ParamDefMagnet): pdm.Out = pdm()



Then I am stupid, and I am just a bunch of implicit stuff. I don't know what I'm talking about! Then I went to the doc and found the magnet pattern. Then I seemed to have seen hope. Click it. Let's take a long e article and feel timid! However, I still finished reading it later. Simply put, it is Scala's design pattern to solve some shortcomings caused by the Type erasure of traditional method overloading. Then, because 'Age. As [int] returns the namereceptacle [int] type, the "overload" method is found.

implicit def forNR[T](implicit fsod: FSOD[T]) = extractParameter[NameReceptacle[T], T] { nr ?    filter(nr.name, fsod)  }
Can you see that it requires an implicit fsod? This is the thing.

import spray.httpx.unmarshalling.{ FromStringOptionDeserializer ? FSOD, _ }
type FromStringOptionDeserializer[T] = Deserializer[Option[String], T]

It is clear that spray has no reason to convert string to a for any type. It turns out that a deserializer is needed to do this. Because it is implicit, you do not need to write it out. 'Age. As [int] should be the implicit function that defines deserializer [Option [String], int] by default, which converts string to int. If no error is reported for date, deserializer [Option [String], date] is not available. Let's take a look at the definition.

implicit def string2Date = new Deserializer[Option[String], Date] {    override def apply(v1: Option[String]): Deserialized[Date] = v1 match {      case None => Left(ContentExpected)      case Some(str) => {        val sdf = new SimpleDateFormat("yyyy-MM-dd")        try {          val date = sdf.parse(str)          Right(date)        } catch {          case _: Throwable => Left(MalformedContent("format yyyy-MM-dd"))        }      }    }  }



Compile again, no problem, run OK!

Later, we found that there is a method in object deserializer that can "Upgrade" the common function F: A => B to deserializer.

implicit def fromFunction2Converter[A, B](implicit f: A ? B) =    new Deserializer[A, B] {      def apply(a: A) = {        try Right(f(a))        catch {          case NonFatal(ex) ? Left(MalformedContent(ex.toString, ex))        }      }    }



Therefore, it can be simplified

implicit def str2Date(str: String) = {    val sdf = new SimpleDateFormat("yyyy-MM-dd")      sdf.parse(str)  }



It looks refreshing!


Finally, let's talk about a small trick. At first I didn't understand the type of 'Age. As [int]. One way is to press Ctrl + B to see it. Another way is to define

val x = ‘age.as[Int]



Then move the mouse to X, ALT + enter, and select "add type annotation to value definition ".

val x: NameReceptacle[Int] = ‘age.as[Int]



This is convenient in some cases.


Scala is indeed very powerful and flexible, with a high learning curve and continuous efforts ........




Spray parameter conversion

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.