{ "title":"Penne with cocktail tomatoes, Rucola and Goat cheese", "details":{ "cuisine":"italian", "vegetarian":true }, "ingredients":[{ "label":"Penne", "quantity":"250g" },{ "label":"Cocktail tomatoes", "quantity":"300g" },{ "label":"Rucola", "quantity":"2 handful" },{ "label":"Goat cheese", "quantity":"200g" },{ "label":"Garlic cloves", "quantity":"2 tsps" }], "steps":[ "Cook noodles until aldente.", "Quarter the tomatoes, wash the rucola, dice the goat's cheese and cut the garlic.", "Heat olive oil in a pan, add the garlic and the tomatoes and steam short (approx. for 5 minutes).", "Shortly before the noodles are ready add the rucola to the tomatoes.", "Drain the noodles and mix with the tomatoes, finally add the goat's cheese and serve." ] }
scala> implicitdefdetails2JValue(rd: RecipeDetails): JValue = Extraction.decompose(rd) warning: there was one feature warning; re-run with -feature for details details2JValue: (rd: RecipeDetails)org.json4s.JValue
scala> (recipeJson \ "steps").extract[List[String]] res13: List[String] = List(Cook noodles until aldente., Quarter the tomatoes, wash the rucola,dice the goat's cheese ..., Heat olive oil in a pan, add the garlic and the tomatoes and ..., Shortly before the noodles are ready add the rucola to the ..., Drain the noodles and mix with the tomatoes,finally add the ...)
scala> JNothing.extract[String] org.json4s.package$MappingException: Did not find value which can be converted into java.lang.String at org.json4s.reflect.package$.fail(package.scala:95) at org.json4s.Extraction$$anonfun$org$json4s$Extraction$$convert$2.apply(Extraction.scala:744) at org.json4s.Extraction$$anonfun$org$json4s$Extraction$$convert$2.apply(Extraction.scala:744) at scala.Option.getOrElse(Option.scala:121) at org.json4s.Extraction$.org$json4s$Extraction$$convert(Extraction.scala:744) at org.json4s.Extraction$$anonfun$extract$7.apply(Extraction.scala:403) at org.json4s.Extraction$$anonfun$extract$7.apply(Extraction.scala:401) at org.json4s.Extraction$$anonfun$customOrElse$1.apply(Extraction.scala:646) at org.json4s.Extraction$$anonfun$customOrElse$1.apply(Extraction.scala:646) at scala.PartialFunction$class.applyOrElse(PartialFunction.scala:123) at scala.collection.AbstractMap.applyOrElse(Map.scala:59) at org.json4s.Extraction$.customOrElse(Extraction.scala:646) at org.json4s.Extraction$.extract(Extraction.scala:401) at org.json4s.Extraction$.extract(Extraction.scala:40) at org.json4s.ExtractableJsonAstNode.extract(ExtractableJsonAstNode.scala:21) ... 40 elided
import org.scalatra._ import org.scalatra.json._ import org.json4s._ import scalaz.{-\/, \/-} import scalaz.Scalaz._ traitMyJsonScalazRoutesextendsScalatraBasewithJacksonJsonSupport{ // be able to handle scalaz' \/ as return value, simply unwrap the value from the container overridedefrenderPipeline: RenderPipeline = ({ case \/-(r) => r case -\/(l) => l }: RenderPipeline) orElse super.renderPipeline
post("/foods_alt") { for { // short-circuits with BadRequest when optional extraction fails label <- (parsedBody \ "label").extractOpt[String] \/> BadRequest() fairTrade <- (parsedBody \ "fairTrade").extractOpt[Boolean] \/> BadRequest() tags <- (parsedBody \ "tags").extractOpt[List[String]] \/> BadRequest() } yieldOk((label, fairTrade, tags)) // yields an ok when all previous steps succeed } }
/** Represents a disjunction: a result that is either an `A` or a `B`. * * An instance of `A` [[\/]] B is either a [[-\/]]`[A]` (aka a "left") or a [[\/-]]`[B]` (aka a "right"). * * A common use of a disjunction is to explicitly represent the possibility of failure in a result as opposed to * throwing an exception. By convention, the left is used for errors and the right is reserved for successes. * For example, a function that attempts to parse an integer from a string may have a return type of * `NumberFormatException` [[\/]] `Int`. However, since there is no need to actually throw an exception, the type (`A`) * chosen for the "left" could be any type representing an error and has no need to actually extend `Exception`. * * `A` [[\/]] `B` is isomorphic to `scala.Either[A, B]`, but [[\/]] is right-biased for all Scala versions, so methods * such as `map` and `flatMap` apply only in the context of the "right" case. This right bias makes [[\/]] more * convenient to use than `scala.Either` in a monadic context in Scala versions <2.12. Methods such as `swap`, * `swapped`, and `leftMap` provide functionality that `scala.Either` exposes through left projections. * * `A` [[\/]] `B` is also isomorphic to [[Validation]]`[A, B]`. The subtle but important difference is that [[Applicative]] * instances for [[Validation]] accumulates errors ("lefts") while [[Applicative]] instances for [[\/]] fail fast on the * first "left" they evaluate. This fail-fast behavior allows [[\/]] to have lawful [[Monad]] instances that are consistent * with their [[Applicative]] instances, while [[Validation]] cannot. */
/** A left disjunction * * Often used to represent the failure case of a result */ finalcaseclass-\/[+A](a: A) extends (A \/ Nothing)
/** A right disjunction * * Often used to represent the success case of a result */ finalcaseclass\/-[+B](b: B) extends (Nothing \/ B)
//scalaz.syntax.std.OptionOps.scala finaldef\/>[E](e: => E): E \/ A = o.toRight(self)(e)
finaldef<\/[B](b: => B): A \/ B = o.toLeft(self)(b)
//scalaz.std.Option.scala finaldeftoRight[A, E](oa: Option[A])(e: => E): E \/ A = oa match { caseSome(a) => \/-(a) caseNone => -\/(e) }
finaldeftoLeft[A, B](oa: Option[A])(b: => B): A \/ B = oa match { caseSome(a) => -\/(a) caseNone => \/-(b) }
//org.scalatra.ActionResult.scala objectBadRequest{ defapply(body: Any = Unit, headers: Map[String, String] = Map.empty) = ActionResult(400, body, headers) }
objectOk{ defapply(body: Any = Unit, headers: Map[String, String] = Map.empty) = ActionResult(200, body, headers) }
Begin of 个人理(cai)解(xiang)(不保证正确性
A / B 和 scala.Either[A,B]同构,返回的结果是[[-/]][A] ,或者是 [[/-]][B] .
val hints = ShortTypeHints(List( classOf[Gram], classOf[Tablespoon], classOf[Teaspoon], classOf[Handful])) // hints: org.json4s.ShortTypeHints = ShortTypeHints(List(class Gram, class Tablespoon, class Teaspoon, class Handful))
implicitval formats = DefaultFormats.withHints(hints) val amountsJson = decompose(amounts)