How to output JSON from Slick query result? - json

I'm a newbie when it comes to Scala and right now trying to learn Slick. I have a database set up much like in the Slick tutorial and querying it with
val users:TableQuery[user] = TableQuery[user]
How do I output users -value in to JSON from Play framework? I have tried defining case class for user and making reader+writer for userFormat = Json.format[user] but I have no clue where I'm going wrong or anything. I've done similar kind of stuff with Spray.IO and it seemed simple and straightforward there, but I want to learn how to do it with Play and Slick and I am completely lost :(
Here is my Tables.scala:
package assets
import org.joda.time.DateTime
import play.api.libs.json._
import scala.slick.driver.MySQLDriver.simple._
import com.github.tototoshi.slick.MySQLJodaSupport._
import scala.slick.lifted.{ProvenShape}
case class user
(
id:Int,
textId:String,
sessionId:String,
stamp:DateTime
)
class users(tag: Tag) extends Table[(Int, String, String, DateTime)](tag, "USER") {
implicit object userFormat extends Format[user] {
def writes(a: user): JsValue = {
Json.obj(
"id" -> JsNumber(a.id),
"textId" -> JsString(a.textId),
"sessionId" -> JsString(a.sessionId),
"stamp" -> JsString(a.stamp.toString())
)
}
def reads(json: JsValue): user = user(
(json \ "id").as[Int],
(json \ "textId").as[String],
(json \ "sessionId").as[String],
(json \ "stamp").as[DateTime]
)
}
def id: Column[Int] = column[Int]("id", O.PrimaryKey)
def textId: Column[String] = column[String]("textId")
def sessionId: Column[String] = column[String]("sessionId")
def stamp: Column[DateTime] = column[DateTime]("stamp")
def * : ProvenShape[(Int, String, String, DateTime)] = (id,textId,sessionId,stamp)
}

First of all, please add some context to your question as it's very hard to see what is not working (e.g. do you get compilation errors? Do you get exceptions?).
With respect to the question content, you should think of getting data from slick and translating it into JSON as two totally independent steps; in fact, there is nothing in slick that will help you in making JSON out of your case classes.
Given that, you will need to run your slick queries and get case class instances for your types out of them, e.g. you should get a Seq[user]. To convert that to JSON you should invoke Json.toJson(myUserSeq). There is one thing that will probably get in your way for what I can see in your code: to have the Format correctly in scope you should put it in the companion object of your case class, e.g.:
case class User(...)
object User {
implicit object format extends Format[User] { ... }
}
As a sideline, please be aware of the language's coding standards if you want people to help you and your code to be readable (e.g. having lower-case class names in your code makes it very hard to follow).

Related

How to add a custom marshaller to akka http?

As a beginner to both scala and akka-http, I am trying to hook into the serialization aka marshalling process.
The project uses akka#2.5.2 and akka-http#10.0.10". Furthermore, it has the akka-http-spray-json dependency included.
In the codebase, we use Java.Util.Currency (It may be deprecated which is not important as I'd still like to know how to add a custom marshaller.)
Given this example controller:
def getCurrencyExample: Route = {
path("currencyExample") {
val currency: Currency = Currency.getInstance("EUR")
val code: String = currency.getCurrencyCode
val shouldBeFormated = collection.immutable.HashMap(
"currencyCode" -> code,
"currencyObject" -> currency
)
complete(shouldBeFormated)
}
}
I get a response like this where the currency object becomes empty:
{
currencyObject: { },
currencyCode: "EUR",
}
I expect something like:
{
currencyObject: "EUR",
currencyCode: "EUR",
}
The currency object should be transformed into a JSON string. And since I do not want to transform each response manually, I want to hook into marshalling process and have it done in the background.
I want to add a custom marhaller only for Java.Util.Currency objects, yet even reading up on the docs I am very unsure how to proceed.
There are multiple approaches described, and I am not sure which fits my need, or where to start.
I tried creating my own CurrencyJsonProtocol:
package com.foo.api.marshallers
import java.util.Currency
import spray.json.{DefaultJsonProtocol, JsString, JsValue, RootJsonFormat}
object CurrencyJsonProtocol extends DefaultJsonProtocol {
implicit object CurrencyJsonFormat extends RootJsonFormat[Currency] {
override def read(json: JsValue): Currency = {
Currency.getInstance(json.toString)
}
override def write(obj: Currency): JsValue = {
JsString(obj.getCurrencyCode)
}
}
}
yet the mere existence of the file breaks my project:
[error] RouteDefinitons.scala:90:16: type mismatch;
[error] found : scala.collection.immutable.HashMap[String,java.io.Serializable]
[error] required: akka.http.scaladsl.marshalling.ToResponseMarshallable
[error] complete(shouldBeFormated)
[error] ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed
and I have no idea why. (It was crashing due to my package name being called marshaller. That completely broke the compilation of the project.
From what I understand, you have all the pieces, you just need to put them together.
Spray json provides support for marshalling common types, such as Int, String, Boolean, List, Map, etc. But it doesn't know how to marshall 'Currency'. And to solve that you have created a custom marshaller for 'Currency' objects. You just need to plug it in the right place. All that you have to do is import the marshaller from your CurrencyJsonProtocol into your Controller like below:
import CurrencyJsonProtocol._
Also make sure you have the below imports as well:
import spray.httpx.SprayJsonSupport._
import spray.json.DefaultJsonProtocol._
And spray-json should automatically pick that up.
To understand how it works, you need to understand about implicits in scala. Although it looks like magic when you come from java-world like me, I can assure you it's not.
I´m using Spray support for years. Maybe i should try another one. Anyway, in Spray, a custom formatter for a type is simple. An example of the squants.market.currency https://github.com/typelevel/squants
import squants.market.{ Currency, Money }
import squants.market._
trait MoneyJsonProtocol extends DefaultJsonProtocol {
implicit object CurJsonFormat extends JsonFormat[Currency] {
def write(currency: Currency): JsValue = JsString(currency.code)
def read(value: JsValue): Currency = value match {
case JsString(currency) =>
defaultCurrencyMap.get(currency) match {
case Some(c) => c
case None => // throw an exception, for example
}
case _ => // throw another exception, for example
}
}
implicit def toJavaBigDecimal(b: math.BigDecimal): java.math.BigDecimal = b.underlying
}
Do you have a JsonFormat[Currency]? If yes, just fix it...
If not, you should follow the doc and create:
as domain model, specific result type to hold the answer e.g. case class CurrencyResult(currency: Currency, code: String)
in trait JsonSupport: a JsonFormat[Currency]
in trait JsonSupport: a JsonFormat[CurrencyResult]
As an alternative to point 1 above, you can probably type your map as: Map[String, JsValue].

Json Writes in Play 2.1.1

I started using the Playframework recently and am implementing a site using Play 2.1.1 and Slick 1.0.0. I'm now trying to wrap my head around Json Writes as I want to return Json in one of my controllers.
I've been looking at several references on the subject (like this one and this one but can't figure out what I'm doing wrong.
I have a model looking like this:
case class AreaZipcode( id: Int,
zipcode: String,
area: String,
city: String
)
object AreaZipcodes extends Table[AreaZipcode]("wijk_postcode") {
implicit val areaZipcodeFormat = Json.format[AreaZipcode]
def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
def zipcode = column[String]("postcode", O.NotNull)
def area = column[String]("wijk", O.NotNull)
def city = column[String]("plaats", O.NotNull)
def autoInc = * returning id
def * = id ~ zipcode ~ area ~ city <> (AreaZipcode.apply _, AreaZipcode.unapply _)
}
You can see the implicit val which I'm trying to use, but when I try to return the Json in my controller by doing this:
Ok(Json.toJson(areas.map(a => Json.toJson(a))))
I'm somehow still confronted with this errormessage:
No Json deserializer found for type models.AreaZipcode. Try to implement an implicit Writes or Format for this type.
I've tried several other ways to implement the Writes. For instance, I've tried the following instead of the implicit val from above:
implicit object areaZipcodeFormat extends Format[AreaZipcode] {
def writes(a: AreaZipcode): JsValue = {
Json.obj(
"id" -> JsObject(a.id),
"zipcode" -> JsString(a.zipcode),
"area" -> JsString(a.area),
"city" -> JsString(a.city)
)
}
def reads(json: JsValue): AreaZipcode = AreaZipcode(
(json \ "id").as[Int],
(json \ "zipcode").as[String],
(json \ "area").as[String],
(json \ "city").as[String]
)
}
Can someone please point me in the right direction?
JSON Inception to the rescue! You only need to write
import play.api.libs.json._
implicit val areaZipcodeFormat = Json.format[AreaZipcode]
That's it. No need to write your own Reads and Writes anymore, thanks to the magic of Scala 2.10 macros. (I recommend that you read Play's documentation on Working with JSON, it explains a lot.)
Edit:
I didn't notice you already had the Json.format inside the AreaZipcodes object. You either need to move that line out of AreaZipcodes or import it into your current context, i.e.
import AreaZipcodes.areaZipcodeFormat

Error working with JSON in Play 2

I am trying to serialize / deserialize using JSON and the Play Framework 2.1.0 and Scala 2.10. I am using Anorm, and I have a pretty simple Object that I want to store in a database. The Order is very simple:
case class Order(id: Pk[Long] = NotAssigned, mfg: String, tp: String)
In my controller, I am trying to build a REST interface to be able to accept and send an Order instance (above) as JSON. In there, I have the following code:
implicit object PkFormat extends Format[Pk[Long]] {
def reads(json: JsValue):Pk[Long] = Id(json.as[Long])
def writes(id: Pk[Long]):JsNumber = JsNumber(id.get)
}
However, this is failing to compile when I run "play test" with the following:
overriding method reads in trait Reads of type (json: play.api.libs.json.JsValue)play.api.libs.json.JsResult[anorm.Pk[Long]];
[error] method reads has incompatible type
[error] def reads(json: JsValue):Pk[Long] = Id(json.as[Long])
Does anyone know why this is happening?
I have a lot of experience with JAXB, but I am realtively new to Play and Scala, and I haven't been able to find any answers so far. This seems like a pretty simple use case, actually I was hoping there would be a simpler solution (like Annotations), but I wasn't able to find one (at least not yet)
Any help is greatly appreciated!
Thanks
play.api.libs.json.Reads trait defines reads method as:
def reads(json : play.api.libs.json.JsValue) : play.api.libs.json.JsResult[A]
Therefore, the response of reads method is expected to be JsResult[A], not A; that is, JsResult[Pk[Long]] and not Pk[Long]. In a case of success, you'll want to return this:
implicit object PkFormat extends Format[Pk[Long]] {
def reads(json: JsValue):JsResult[Pk[Long]] = JsSuccess(Id(json.as[Long]))
def writes(id: Pk[Long]):JsNumber = JsNumber(id.get)
}

Rendering JSON with Play! and Scala

I have a simple question regarding rendering JSON object from a Scala class. Why do I have to implemet deserializer ( read, write ).
I have the following case class:
case class User(firstname:String, lastname:String, age:Int)
And in my controller:
val milo:User = new User("Sam","Fisher",23);
Json.toJson(milo);
I get compilation error: No Json deserializer found for type models.User. Try to implement an implicit Writes or Format for this type.
In my previous project I had to implement a reader,writer object in the class for it to work and I find it very annoying.
object UserWebsite {
implicit object UserWebsiteReads extends Format[UserWebsite] {
def reads(json: JsValue) = UserWebsite(
(json \ "email").as[String],
(json \ "url").as[String],
(json \ "imageurl").as[String])
def writes(ts: UserWebsite) = JsObject(Seq(
"email" -> JsString(ts.email),
"url" -> JsString(ts.url),
"imageurl" -> JsString(ts.imageurl)))
}
}
I really recommend to upgrade to play 2.1-RC1 because here, JSON writers/readers are very simple to be defined (more details here)
But in order to help you to avoid some errors, I will give you a hint with imports:
- use these imports only! (notice that json.Reads is not included)
import play.api.libs.json._
import play.api.libs.functional.syntax._
import play.api.libs.json.Writes._
and you only have to write this code for write/read your class to/from Json (of course you will have User instead of Address:
implicit val addressWrites = Json.writes[Address]
implicit val addressReads = Json.reads[Address]
Now, they will be used automatically:
Example of write:
Ok(Json.toJson(entities.map(s => Json.toJson(s))))
Example of read(I put my example of doing POST for creating an entity by reading json from body) please notice addressReads used here
def create = Action(parse.json) { request =>
request.body.validate(addressReads).map { entity =>
Addresses.insert(entity)
Ok(RestResponses.toJson(RestResponse(OK, "Succesfully created a new entity.")))
}.recover { Result =>
BadRequest(RestResponses.toJson(RestResponse(BAD_REQUEST, "Unable to transform JSON body to entity.")))
}
}
In conclusion, they tried (and succeded) to make things very simple regarding JSON.
If you are using play 2.0.x you can do
import com.codahale.jerkson.Json._
generate(milo)
generate uses reflection to do it.
In play 2.1 you can use Json.writes to create a macro for that implicit object you had to create. No runtime reflection needed!
import play.api.libs.json._
import play.api.libs.functional.syntax._
implicit val userWrites = Json.writes[User]
Json.toJson(milo)
I have been using jerkson (which basically is wrapper to jackson) in my project to convert objects to json string.
The simplest way to do that is:
import com.codehale.jerkson.Json._
...
generate(milo)
...
If you need to configure the ObjectMapper (e.g. adding custom serializer/deserializer, configuring output format, etc.), you can do it by creating object which extends com.codehale.jerkson.Json class.
package utils
import org.codehaus.jackson.map._
import org.codehaus.jackson.{Version, JsonGenerator, JsonParser}
import com.codahale.jerkson.Json
import org.codehaus.jackson.map.module.SimpleModule
import org.codehaus.jackson.map.annotate.JsonSerialize
object CustomJson extends Json {
val module = new SimpleModule("CustomSerializer", Version.unknownVersion())
// --- (SERIALIZERS) ---
// Example:
// module.addSerializer(classOf[Enumeration#Value], EnumerationSerializer)
// --- (DESERIALIZERS) ---
// Example:
// module.addDeserializer(classOf[MyEnumType], new EnumerationDeserializer[MyEnumType](MyEnumTypes))
mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL)
mapper.setSerializationConfig(mapper.getSerializationConfig.without(SerializationConfig.Feature.WRITE_NULL_MAP_VALUES))
mapper.registerModule(module)
}
To use it in your codes:
import utils.CustomJson._
...
generate(milo)
...
In fact, this is very simple. Firstly import:
import play.api.libs.json._
Thanks to the fact, that User is a case class you can automatically create Json writes using Json.writes[]:
val milo:User = new User("Millad","Dagdoni",23)
implicit val userImplicitWrites = Json.writes[User]
Json.toJson(milo)
I haven't found it in the docs, but here is the link to the api: http://www.playframework.com/documentation/2.2.x/api/scala/index.html#play.api.libs.json.Json$
In your case, I'd use the JSON.format macro.
import play.api.libs.json._
implicit val userFormat = Json.format[User]
val milo = new User("Sam", "Fisher", 23)
val json = Json.toJson(milo)

Play2 does not find my implicit Reads or Format for JSON

This is my Search Object:
package models.helper
import play.api.libs.json.Format
import play.api.libs.json.JsValue
import play.api.libs.json.JsObject
import play.api.libs.json.JsString
case class Search (name: String, `type`:String){
implicit object SearchFormat extends Format[Search] {
def reads(json: JsValue): Search = Search(
(json \ "name").as[String],
(json \ "type").as[String]
)
def writes(s: Search): JsValue = JsObject(Seq(
"name" -> JsString(s.name),
"type" -> JsString(s.`type`)
))
}
}
I'm trying ot use this class when calling a webservice using WS:
val search = response.json.as[Search]
But the scala compiler keeps complaining on this line:
No Json deserializer found for type models.helper.Search. Try to
implement an implicit Reads or Format for this type.
Could anybody tell me what I'm doing wrong?
got the example from https://sites.google.com/site/play20zh/scala-developers/working-with-json
this thread discusses the same issue but gives no solution, what example on what site? https://groups.google.com/forum/?fromgroups#!topic/play-framework/WTZrmQi5XxY
Indeed the example is wrong. You need your implicit Format[Search] value to be available in the implicit scope.
In your case the Format[Search] is defined as a nested value of the class Search, so you can reach it only from an instance of Search.
So, what you want to do is to define it in another place, where it could be referenced without having to create an instance of Search, e.g. in a Formats object:
object Formats {
implicit SearchFormat extends Format[Search] {
…
}
}
Then you can use it as follows:
import Formats.SearchFormat
val search = response.json.as[Search]
You can also get rid of the import tax by defining the Format[Search] value in the companion object of the Search class. Indeed the Scala compiler automatically looks in companion objects of type parameters when it needs an implicit value of a given type:
case class Search(name: String, `type`: String)
object Search {
implicit object SearchFormat extends Format[Search] {
…
}
}
Then you can use it without having to import it:
val search = response.json.as[Search]