spray / spray-json Goto Github PK
View Code? Open in Web Editor NEWA lightweight, clean and simple JSON implementation in Scala
License: Apache License 2.0
A lightweight, clean and simple JSON implementation in Scala
License: Apache License 2.0
This will allow type-class based marshalling architecture to constrain applicability to type actually producing valid JSON root objects ...
It would be really nice if case classes were supported without the need to explicitly register case classes with the relevant ProductFormats
.
Lift JSON seems to be able to do this.
if I have a sealed trait
sealed trait Failure
and if I have a bunch of implementations, all case classes, is there a nice way to support marshalling and unmarshalling? I ended up writing one hell of a hack and it occurs to me you might have an elegant solution (my hack involves switching on the class type and inserting the classname into the JSON, then switching on the class name from the JSON and using hard-coded clasasnames to then switch to get the right unmarshaller)
Awesome project!
Just running through the Usage examples in your README, it would be useful to know that you need to import spray.json.DefaultJsonProtocol._
in order to get things like List(1, 2, 3).toJson
to work.
It might also be helpful for cut-and-pasters like me if you could include the sbt snippet for adding the Spray resolver: resolvers += "spray" at "http://repo.spray.io/"
.
This is more of a question than a report of any kind: how come Spray-JSON isn't reusing the code in scala.util.parsing
?
It would be really cool if Spray used the built-in data structures.
Is there a convertor for going to/from the Spray JSON to Scala JSON formats? Some implicits would be nice here, although obviously less optimal than just using the Scala objects.
see this thread
The implicit tuple7Format in StandardFormats is repeating element 6 instead of writing element 7.
Currently the JsonFormatter stops at 15 parameters for a case class. I propose that it be increased to 22, which is the global parameter limit that Scala has for all functions.
Hi,
There's a link in the README that is broken. It is here : https://github.com/spray/spray-json#api-documentation
Hi,
i try to download the latest build for scala via maven and this pom.xml, without sucess ..
is it only for sbt ? is there any plan to make a compatible maven version ?
<repositories>
<repository>
<id>spray repo</id>
<name>Spray Repository</name>
<url>http://repo.spray.io/</url>
</repository>
</repositories>
<dependency>
<groupId>io.spray</groupId>
<artifactId>spray-json_${scala.version}</artifactId>
<version>1.2.2</version>
</dependency>
This link is giving 404:
Hi!
The archetype-catalog.xml file only contains the string "ArchetypeContentGenerator".
Perhaps I discovered a bug. I get Null Pointer Exception when I'm trying to get json of an object that has field of type of itself. Example is:
case class TestItem(subitems: Option[List[TestItem]])
object MyJsonProtocol extends DefaultJsonProtocol {
implicit val testItemFormat: RootJsonFormat[TestItem] = jsonFormat(TestItem, "subitems")
}
import MyJsonProtocol._
object TestNPE {
def main(args: Array[String]) {
val subitems = List(TestItem(None))
val item: TestItem = TestItem(Option(subitems))
val jsonAst = item.toJson
val json = jsonAst.prettyPrint
println(json)
}
}
And call-stack is this
Exception in thread "main" java.lang.NullPointerException
at spray.json.PimpedAny.toJson(package.scala:40)
at spray.json.CollectionFormats$$anon$1$$anonfun$write$1.apply(CollectionFormats.scala:26)
at spray.json.CollectionFormats$$anon$1$$anonfun$write$1.apply(CollectionFormats.scala:26)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.immutable.List.foreach(List.scala:309)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:244)
at scala.collection.AbstractTraversable.map(Traversable.scala:105)
at spray.json.CollectionFormats$$anon$1.write(CollectionFormats.scala:26)
at spray.json.CollectionFormats$$anon$1.write(CollectionFormats.scala:25)
at spray.json.PimpedAny.toJson(package.scala:40)
at spray.json.StandardFormats$OptionFormat.write(StandardFormats.scala:34)
at spray.json.StandardFormats$OptionFormat.write(StandardFormats.scala:32)
at spray.json.ProductFormats$class.productElement2Field(ProductFormats.scala:473)
at spray.json.MyJsonProtocol$.productElement2Field(TestNPE.scala:5)
at spray.json.ProductFormats$$anon$1.write(ProductFormats.scala:32)
at spray.json.ProductFormats$$anon$1.write(ProductFormats.scala:30)
at spray.json.PimpedAny.toJson(package.scala:40)
at spray.json.TestNPE$.main(TestNPE.scala:18)
at spray.json.TestNPE.main(TestNPE.scala)
I tried to fix it myself but my knowledge of Scala is not strong enough yet. NPE happens here when it's attempting to convert inner TestItem
. Function parameter write
at that moment is null
.
I don't know why it doesn't use my implicit instead.
Jackson allows you to marshal and unmarshal the Number type, while Spray JSON doesn't.
see this thread
I might be missing something:
val json = """{ "some": "JSON source" }""".toJson
json should equal(json.toString.toJson)
But it looks like it's escaping the slashes before the already escaped quotes:
"{ "some": "JSON source" }" did not equal ""{ \"some\": \"JSON source\" }""
Please add something like the following to BasicFormats
: UUIDs are so widely used that they must be on par with some of the other types in that file.
trait UuidMarshalling {
implicit object UuidJsonFormat extends JsonFormat[UUID] {
def write(x: UUID) = JsString(x toString ())
def read(value: JsValue) = value match {
case JsString(x) => UUID.fromString(x)
case x => deserializationError("Expected UUID as JsString, but got " + x)
}
}
}
probably best to encode it as JSON null
See discussion: https://groups.google.com/d/msg/spray-user/zTORNzACIp0/qTmDWi9TZ8EJ
Experimentation branch:
https://github.com/jrudolph/spray/tree/feature/json-case-class-implicit-macro
I wrote a little app to speed profile Spray JSON for simple case classes – answer = Blindingly Fast!!!
However, when I used Random.nextString to generate test String data the marshalling to/from a String (containing JSON data) failed. I can provide a test case if you want to see this in action, but this might be a simple case of you having an answer straight away.
My workaround was to include only printable characters – but I'm now concerned about non-ASCII UTF8 characters.
I would like to use a custom marshaller for BigInt and BigDecimal, to use JsString instead of JsNumber.
The reason for this is because we are re-using Spray JSON marshallers to serialise to/from MongoDB objects. Despite claims that BSON is a superset of JSON, it doesn't support arbitrary precision numbers. i.e. there is no such thing as BsonNumber
– it's all ints or longs, floats or doubles. The workaround is that any arbitrary precision numbers must be serialised as String in MongoDB.
Unfortunately, because the implicit JsonFormat
s are defined as implicit object
, the scala compiler will not let me override them. If they were implicit val
, I believe this would be ok.
For an example see https://groups.google.com/forum/?hl=en#!topic/spray-user/YETwMSS9w3E
Hi there, was trying to follow the example in the README however I'm running into a problem, checkout my REPL session:
$ scala -cp /.ivy2/cache/cc.spray.json/spray-json_2.9.1/jars/spray-json_2.9.1-1.0.1.jar:/.ivy2/cache/org.parboiled/parboiled-scala/jars/parboiled-scala-1.0.2.jar:~/.ivy2/cache/org.parboiled/parboiled-core/jars/parboiled-core-1.0.2.jar
Welcome to Scala version 2.9.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_26).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import cc.spray.json._
import cc.spray.json._
scala> List(1,2,3).toJson
:11: error: Cannot find JsonWriter or JsonFormat type class for List[Int]
List(1,2,3).toJson
Any thoughts on what I might be doing wrong? Are there extra steps I need to take? Thanks in advance.
It would be fantastic if there were a convertor to go between Spray JSON's JsValue
and Jackson's JsonNode
. That way, Spray JSON could be more efficiently leveraged in traditional containers (with json2xml a one-way bridge to JAXB). Currently, in order to use Spray JSON in traditional containers requires marshalling to/from String
There's probably a perfectly good explanation for this, and I really am just looking to understand.
I can parse JSON documents with mixed types, like so:
scala> val j1 = JsonParser( """[1,2]""" )
j1: cc.spray.json.JsValue = [1,2]
scala> val j2 = JsonParser( """[1,2.0]""" )
j2: cc.spray.json.JsValue = [1,2.0]
scala> val j3 = JsonParser( """[1,"two"]""" )
j3: cc.spray.json.JsValue = [1,"two"]
But creating objects from the AST doesn't work as I would expect:
scala> j1.fromJson[ List[Int] ]
res16: List[Int] = List(1, 2)
scala> j2.fromJson[ List[Float] ]
res17: List[Float] = List(1.0, 2.0)
scala> j3.fromJson[ List[Any] ]
:15: error: Cannot find JsonReader or JsonFormat type class for List[Any]
What I think I want is to be able to take such an AST and convert it to a List[Any], with each value converted to its "obvious" type. So in the above example I would like to get a List containing an Int and a String, i.e.
List(1, "two") // what I was expecting
Same for Maps, etc.
Am I thinking about things the wrong way, wanting to do one thing when there's a better way? Or is there a reason (perhaps implicit resolution) why fromJson[ List[Any] ] couldn't/shouldn't behave as I expect?
Thanks for any help.
I am not sure if it’s possible, but would be great if spray-json supported case classes with some of the parameters having default values. What I mean is if we have
case class Test(a: Int = 3, b: Int)
then
{"b": 4}
should deserialize into
Test(3, 4)
instead of failing.
All jsonFormatN methods throw a MatchError if one tries to call them with a polymorphic class. Example:
case class Box[A](a:A)
jsonFormat1(Box[Int])
I wrote this to support no-arg case classes, is it really needed?
case class SingletonCaseClassFormat[T](instance: T) extends JsonFormat[T] {
override def write(obj: T) = JsString(instance.getClass.getSimpleName)
override def read(json: JsValue) = json match {
case JsString(x) =>
if(x != instance.getClass.getSimpleName)
deserializationError("Expected %s, but got %s" format (instance.getClass.getSimpleName, x))
instance
case x => deserializationError("Expected JsString, but got " + x)
}
}
... and this way make JsValue creation statically typed rather than resorting to RuntimeExceptions if conversion is impossible
Hi,
i use maven (no sbt). I maven repo is only version 1.0.1 but I need version 1.1.1. From where i cant simple download jar ?
Despite how many JSON libraries there are, it is nice to see a Scala library aimed at being straightforward and lightweight.
For what it's worth, here are two suggestions that I personally feel would go to making this even better:
Add printing methods to JSON AST object.
The syntax:
val json = PrettyPrinter(jsonAst)
although common to many JSON libraries and allowing for infinite printing libraries in the future, feels very awkward. Given that pretty printing and compact printing are probably 99% of what people want, why not also offer:
val json = jsonAst.prettyPrint
or
val json = jsonAst.compactPrint
More readable code naming of fromJson
The code:
val myObject = jsonAst.fromJson[MyObjectType]
for someone unfamiliar to this library, reads as though the MyObjectType
is some form of JSON rather than the type to be convert to from JSON. How about naming it something like convertTo
:
val myObject = jsonAst.convertTo[MyObjectType]
I have a gateway server which communicates with sms, email, database and asp.net servers that has different versions running on different ports. This gateway then sends various responses to different apps. My problem is in application.conf
Current implementation is as below:
app1config{
Server1Port
Server2Host
Server3Path
Server3Host
Server3Port
app1Config's Port Number
Server1Path
Server1LoginUser
Server1LoginPassword
emailFromAddress
emailSignature
Server2User
Server2Password
Server2BusinessCode
Server2Setting
Server2Config
}
and this is repeated for
app2congig{
}
app3config{
}
app4config{
}
app5config{
}
The client's requirement is to combine all the settings into one configuration, so that there aren't about 5 versions of the same config.
Now my concern is that spray's strength lies in these different versions whereby the application.conf file is a switch statement and each app#no.config is a case and the main.scala file does not perform much logic except ConfigFactory.load() and place all the variables where needed.
The question is:
By this I mean, say there is a unique setting for each app, say Server2Config can I do this?
Server_Config_For All_Apps {
#Common Settings
Server1Port = "some setting"
Server2Host = "some setting"
Server3Path = "some setting"
Server3Host = "some setting"
Server3Port = "some setting"
case "App#1Server2Config" =>
#Unique Settings
app1ConfigPort Number = "some setting"
Server1Path = "some setting"
Server1LoginUser = "some setting"
Server1LoginPassword = "some setting"
emailFromAddress = "some setting"
emailSignature = "some setting"
Server2User = "some setting"
Server2Password = "some setting"
Server2BusinessCode = "some setting"
Server2Setting = "some setting"
Server2Config = "some setting"
case "Some nth app Server2Config" =>
#Unique Settings
app1ConfigPort Number = "some setting"
Server1Path = "some setting"
Server1LoginUser = "some setting"
Server1LoginPassword = "some setting"
emailFromAddress = "some setting"
emailSignature = "some setting"
Server2User = "some setting"
Server2Password = "some setting"
Server2BusinessCode = "some setting"
Server2Setting = "some setting"
Server2Config = "some setting"
case "App#2Server2Config" =>
#Unique Settings
app1ConfigPort Number = "some setting"
Server1Path = "some setting"
Server1LoginUser = "some setting"
Server1LoginPassword = "some setting"
emailFromAddress = "some setting"
emailSignature = "some setting"
Server2User = "some setting"
Server2Password = "some setting"
Server2BusinessCode = "some setting"
Server2Setting = "some setting"
Server2Config = "some setting"
}
}
Over the last few months using spray-json I had learned the following (incorrect) rule:
null
is allowed iff your type is of the formOption[X]
Today I unlearned this rule when I converted a null
into Double.NaN
(#8) instead triggering an exception, which is what I was expecting to happen. Trying out a bunch of standard formats, I observe these behaviors when deserializing from null
:
JsNull.convertTo[Boolean] -> error
JsNull.convertTo[Int] -> error
JsNull.convertTo[Long] -> error
JsNull.convertTo[Char] -> error
JsNull.convertTo[String] -> error
JsNull.convertTo[Seq[Int]] -> error
JsNull.convertTo[Map[String, Int]] -> error
JsNull.convertTo[(Int, String)] -> error
JsNull.convertTo[Float] -> Float.NaN
JsNull.convertTo[Double] -> Double.NaN
JsNull.convertTo[Unit] -> ()
JsNull.convertTo[Option[Int]] -> None
I think the library's behavior would be less surprising and thus easier to use if the rule above did hold. To that end, I propose:
null
<-> Float.NaN
/Double.Nan
, disabled by defaultnull
-> ()
for Unit
Thoughts? Are there more cases that I'm missing? Is the issue more subtle than this?
Some(None) becomes null, and null becomes None, right?
The URL http://spray.github.com/spray/api/spray-json/, linked from https://github.com/spray/spray-json#api-documentation, is missing.
Hi,
This is my first use of Spray-Json so I didn't know its rules to handle null values.
I want to serialize a non-case class (Hibernate entity). The code looks like:
implicit object EntityJsonFormat extends RootJsonFormat[Entity] {
def write(e: Entity) = {
JsObject(
"id" -> JsNumber(e.id),
"name" -> JsString(e.name),
"desc" -> JsString(e.optional) // this may be null
)
}
And it fails with:
2013-08-25 16:03:33,513 [test-akka.actor.default-dispatcher-2] ERROR [akka.actor.RepointableActorRef] - Error during processing of request HttpRequest(GET,http://localhost:8080/test,List(Host: localhost:8080, Authorization: Basic bWFydGluLmdyaWdvcm92QGp3ZWVrZW5kLmNvbTphc2Rm, User-Agent: curl/7.29.0),EmptyEntity,HTTP/1.1)
java.lang.NullPointerException: null
at spray.json.JsonPrinter$class.firstToBeEncoded$1(JsonPrinter.scala:60) ~[spray-json_2.10-1.2.5.jar:1.2.5]
at spray.json.JsonPrinter$class.printString(JsonPrinter.scala:63) ~[spray-json_2.10-1.2.5.jar:1.2.5]
at spray.json.PrettyPrinter$.printString(PrettyPrinter.scala:68) ~[spray-json_2.10-1.2.5.jar:1.2.5]
at spray.json.JsonPrinter$class.printLeaf(JsonPrinter.scala:52) ~[spray-json_2.10-1.2.5.jar:1.2.5]
at spray.json.PrettyPrinter$.printLeaf(PrettyPrinter.scala:68) ~[spray-json_2.10-1.2.5.jar:1.2.5]
at spray.json.PrettyPrinter$class.spray$json$PrettyPrinter$$print(PrettyPrinter.scala:36) ~[spray-json_2.10-1.2.5.jar:1.2.5]
at spray.json.PrettyPrinter$$anonfun$printObject$2.apply(PrettyPrinter.scala:46) ~[spray-json_2.10-1.2.5.jar:1.2.5]
at spray.json.PrettyPrinter$$anonfun$printObject$2.apply(PrettyPrinter.scala:42) ~[spray-json_2.10-1.2.5.jar:1.2.5]
at spray.json.JsonPrinter$$anonfun$printSeq$1.apply(JsonPrinter.scala:94) ~[spray-json_2.10-1.2.5.jar:1.2.5]
at spray.json.JsonPrinter$$anonfun$printSeq$1.apply(JsonPrinter.scala:92) ~[spray-json_2.10-1.2.5.jar:1.2.5]
at scala.collection.Iterator$class.foreach(Iterator.scala:727) ~[scala-library-2.10.2.jar:na]
at scala.collection.AbstractIterator.foreach(Iterator.scala:1157) ~[scala-library-2.10.2.jar:na]
....
To overcome this NPE I changed my code to:
implicit object EntityJsonFormat extends RootJsonFormat[Entity] {
def write(e: Entity) = {
val optJs =
if (e.optional != null) JsString(e.optional)
else JsNull
JsObject(
"id" -> JsNumber(e.id),
"name" -> JsString(e.name),
"desc" -> optJs
)
}
I have two suggestions:
In any case the NPE should not happen.
it would be great if there were a way to allow sloppy JSON (as used by domain languages such as MongoDB) which doesn't require quotation marks around keys and is also happy with single quotes.
Hi, I'm using spray-json 1.2.2 and get this error:
scala> Map("a" -> Map("b" -> 2), "b" -> Map()).toJson
:14: error: Cannot find JsonWriter or JsonFormat type class for scala.collection.immutable.Map[String,scala.collection.immutable.Map[_ <: String, Int]]
Map("a" -> Map("b" -> 2), "b" -> Map()).toJson
^
Doesn't seem like it should be that hard to fix.
I want to convert a ListMap[String, String] to json string through spray. Since ListMap maintains the insertion order of items, I assumed spray json would also return a json string with the items in order. However it seems spray json does not support this yet. Can anybody let me know if there is any workaround for this?
(I am using spray-json_2.10-1.2.3)
scala> import collection.immutable.ListMap
import collection.immutable.ListMap
scala> import spray.json._
import spray.json._
scala> import DefaultJsonProtocol._
import DefaultJsonProtocol._
scala> val map = ListMap[String, Int]("a" -> 1, "b" -> 2, "c" -> 3)
map: scala.collection.immutable.ListMap[String,Int] = Map(a -> 1, b -> 2, c -> 3)
scala> map.asJson
<console>:16: error: value asJson is not a member of scala.collection.immutable.ListMap[String,Int]
map.asJson
^
Right now there is no protocol that can convert to/from Seq[Any] and Map[String, Any]. This prevents spray-json from being used in many scenarios, unless you code up your own protocol. Spray-json should provide out of the box protocols for these common generics.
I have code that I would like to contribute back for these protocols.
trait A ...
implicit val format = new JsonReader[A] { def read ... }
v.convertTo[A] // Ok
v.convertTo[List[A]] // Cannot find JsonReader or JsonFormat type class for List[A]
The problem is that def listFormat[T :JsonFormat]: RootJsonFormat[List[T]]
lifts JsonFormat
s but not JsonReader
s or JsonWriter
s, and this appears to be the pattern throughout the formats for collections, products, etc.
I see the lift
functions JsonReader[T] => JsonFormat[T]
and JsonWriter[T] => JsonFormat[T]
, but relying on these puts me in a situation when statically I think I have both a reader and writer, but at runtime I discover that I'm actually missing one. To me, static checking is one of the valuable parts of spray-json, so I'm very hesitant to undermine it.
I propose splitting all of the "lifting formats"
(JsonFormat[T], ...) => JsonFormat[F[T, ...]]
into reader-writer pairs
(JsonReader[T], ...) => JsonReader[F[T, ...]]
(JsonWriter[T], ...) => JsonWriter[F[T, ...]]
by turning things like this
implicit def listFormat[T :JsonFormat] = new RootJsonFormat[List[T]] {
def write(list: List[T]) = JsArray(list.map(_.toJson))
def read(value: JsValue) = value match {
case JsArray(elements) => elements.map(_.convertTo[T])
case x => deserializationError("Expected List as JsArray, but got " + x)
}
}
into things like this
implicit def listWriter[T :JsonWriter]: JsonWriter[List[T]] = (list: List[T]) => JsArray(list.map(_.toJson))
implicit def listReader[T :JsonReader]: JsonReader[List[T]] = (value: JsValue) => value match {
case JsArray(elements) => elements.map(_.convertTo[T])
case x => deserializationError("Expected List as JsArray, but got " + x)
}
implicit def listFormat[T :JsonFormat] = rootJsonFormat[List[T]](implicitly, implicitly)
I'd be happy to contribute a patch, and I welcome suggestions for simpler ways to achieve this. ;)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.