Git Product home page Git Product logo

spray-json's Issues

Sealed traits

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)

Documentation: mention DefaultJsonProtocol import, resolver snippet in README

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/".

Reuse code from scala.util.parsing.{ast,json}

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.

tuple7Format write wrong

The implicit tuple7Format in StandardFormats is repeating element 6 instead of writing element 7.

Add JsonFormatter16-22

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.

Maven version for scala 2.10-RC1

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>

NPE when serializing type that references itself

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.

UUID support

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)
    }
  }
}

JSON marshalling/unmarshalling with Random.nextString test data failure

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.

val instead of object for BigInt and BigDecimal

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 JsonFormats 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.

error: Cannot find JsonWriter or JsonFormat type class for List[Int

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.

Jackson convertor

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

Why can't I do fromJson to a List[Any]?

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.

Support default parameters

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.

Singleton (no parameter) case classes

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)
  }
}

Feedback: Printing and .fromJson interfaces

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]

How to Group Sbt Application.conf settings for different apps - Is this Possible? If so What is the Best Approach?

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{

Common Settings

Server1Port
Server2Host
Server3Path
Server3Host
Server3Port

Unique Settings

app1Config's Port Number
Server1Path
Server1LoginUser
Server1LoginPassword
emailFromAddress
emailSignature
Server2User
Server2Password
Server2BusinessCode
Server2Setting
Server2Config
}
and this is repeated for

app2congig{

same setup

}

app3config{

same setup

}

app4config{

same setup

}

app5config{

same setup

}
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:

  1. Do I combine all settings to be used on one port, add more variables and have logic constructs in main.scala to accommodate all these new variables? ...and consequently add more logic throughout the main.scala file for each nth app added.
  2. Or is there a way of introducing logic constructs, like for loops, while loops, if else statements, break and continue in the application.conf file?...and then pull these automatically?

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"
       }
 }
  1. I could maintain 5 versions but have them all use the same port number?... On this one I wouldn't know about overhead in terms of network traffic.
  2. Do I still continue using this setup?
  3. Is there a different way altogether?

Inconsistent behavior when deserializing null

Over the last few months using spray-json I had learned the following (incorrect) rule:

null is allowed iff your type is of the form Option[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:

  • Exposing an option for null <-> Float.NaN/Double.Nan, disabled by default
  • Rejecting null -> () for Unit

Thoughts? Are there more cases that I'm missing? Is the issue more subtle than this?

NullPointerException when passing null to JsString

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:

  1. add require(arg != null) in JsString#apply(String) (and other JsValue impls)
  2. or degrade JsString(null) automatically to JsNull

In any case the NPE should not happen.

non strict JsonParser mode

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.

Cannot convert nested Maps into json

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.

cannot convert ListMap to json string

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
                  ^

Add default protocol support for Seq[Any] and Map[String, Any]

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.

Lift JsonReader/JsonWriter through derived formats

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 JsonFormats but not JsonReaders or JsonWriters, 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. ;)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.