Code Monkey home page Code Monkey logo

jerkson's Introduction

Jerkson

Because I think you should use JSON.

Jerkson is a Scala wrapper for Jackson which brings Scala's ease-of-use to Jackson's features.

Requirements

  • Scala 2.8.2 or 2.9.1
  • Jackson 1.9.x

Setting Up Your Project

Go ahead and add Jerkson as a dependency:

<repositories>
  <repository>
    <id>repo.codahale.com</id>
    <url>http://repo.codahale.com</url>
  </repository>
</repositories>

<dependencies>
  <dependency>
    <groupId>com.codahale</groupId>
    <artifactId>jerkson_${scala.version}</artifactId>
    <version>0.5.0</version>
  </dependency>
</dependencies>

Parsing JSON

import com.codahale.jerkson.Json._

// Parse JSON arrays
parse[List[Int]]("[1,2,3]") //=> List(1,2,3)

// Parse JSON objects
parse[Map[String, Int]]("""{"one":1,"two":2}""") //=> Map("one"->1,"two"->2)

// Parse JSON objects as case classes
// (Parsing case classes isn't supported in the REPL.)
case class Person(id: Long, name: String)
parse[Person]("""{"id":1,"name":"Coda"}""") //=> Person(1,"Coda")

// Parse streaming arrays of things
for (person <- stream[Person](inputStream)) {
  println("New person: " + person)
}

For more examples, check out the specs.

Generating JSON

// Generate JSON arrays
generate(List(1, 2, 3)) //=> [1,2,3]

// Generate JSON objects
generate(Map("one"->1, "two"->"dos")) //=> {"one":1,"two":"dos"}

For more examples, check out the specs.

Handling snake_case Field Names

case class Person(firstName: String, lastName: String)

@JsonSnakeCase
case class Snake(firstName: String, lastName: String)

generate(Person("Coda", "Hale"))   //=> {"firstName": "Coda","lastName":"Hale"}
generate(Snake("Windey", "Mover")) //=> {"first_name": "Windey","last_name":"Mover"}

License

Copyright (c) 2010-2011 Coda Hale

Published under The MIT License, see LICENSE

jerkson's People

Contributors

aryairani avatar codahale avatar imikushin avatar jdanbrown avatar leifwickland avatar manuelbernhardt avatar mattkrae34 avatar moonpolysoft avatar tnm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jerkson's Issues

Mapping a case class param to Map[String,Any]?

Is it possible to map a param to Map[String,Any]?
The use case is that i have a json field called params which i just want to ignore rather than process.
Here's the breaking test case.

import org.junit.{Test, Assert, Before}
import com.codahale.jerkson.Json._

case class Element(title:String, params:Map[String,Any])
@Test
class JsonParserTest{
  @Test
  def testMapAny{
    val result = parse[Element]("""{"title":"foobar", "params":{"one":1,"two":2, "other": "give"}}""")
    println(result)
  }
}

Enumeration Support for Jerkson

It would be a great addition to Jerkson if it supported ser/deser of Scala Enumerations. Sample below:

object Day extends Enumeration {
val Mon, Tues, Wed, Thurs, Fri, Sat, Sun = Value
}

Support for parameterized types

Jerkson can't deserialize into parameterized types. For example (based on ExampleCaseClasses.scala):

case class CaseClassWithList[T](id: Long, list: List[T])
parse[CaseClassWithList[CaseClass]]("""{"id":1,"list":[{"id":1,"name":"Coda"}]}""")

will throw a java.lang.ClassNotFoundException: T. Unlike issue #9, I'd like to be able to hint in the scala code (not in the JSON) that the parameterized type should be a CaseClass. I think something like parse[CaseClassWithList[CaseClass]](arg, List[Class]) where the list of classes would specify the parameterized types that ClassFileParser can't determine from the bytecode.

Thoughts? Is there a better way to do this? I made a commit in my fork of jerkson which has the full (failing) test case if that helps.

Deserialize to Scala collection for values of unknown type

It would be great to be able to deserialize to a Scala collection instead of Java collections when you don't know what your input would be. There are use cases when you know you could have a Map just as well as a List, so your options are either to use parse[JValue] or parse[Any]. The problem is that these both get back java collections, and you can't pattern match them or flatMap them, etc.

Of course, there is the workaround to convert from JValues (or Java collections) to scala collections every time, but you lose some performance.

CaseClassDeserializer: Ctor search fails with Arrays

I use the following case class:

case class TraversePath (start:String, nodes:Array[String], length:Int, relationships:Array[String], end:String)

The Repl returns the following ctor parameter list (code like yours in CaseClassDeserializer)

scala> classOf[TraversePath].getConstructors.apply(0).getParameterTypes.toList.map(t=>t.toString) res9: List[java.lang.String] = List(class java.lang.String, class [Ljava.lang.String;, int, class [Ljava.lang.String;, class java.lang.String)

CaseClassDeserializer expects the following in paramTypes: List(class java.lang.String, class scala.Array, class java.lang.Integer, class scala.Array, class java.lang.String)

coming from SigParser scala.Array will be returned.

So - CaseClassDeserializer will never find the right ctor if it searches for Arrays - right?

Release 0.6.0

It's been almost a year since the release of 0.5.0. There are some commits I would really like to see be made available in a released version.

"Failed to parse pickled Scala signature from: class Person" (Inner/nested case classes are not compatible with Jerkson. Nor do they work in the REPL.)

I added Jerkson 0.3.1 for Scala 2.9.0-1 to my sbt project and then in the sbt console attempted to run the "Parsing Json" samples listed in the jerkson readme. It worked up until the "parse[Person]" bit, the following exception was tossed:

com.codahale.jerkson.util.MissingPickledSig: Failed to parse pickled Scala signature from: class Person
    at com.codahale.jerkson.util.CaseClassSigParser$.findSym(CaseClassSigParser.scala:54)
    at com.codahale.jerkson.util.CaseClassSigParser$.parse(CaseClassSigParser.scala:59)
    at com.codahale.jerkson.deser.CaseClassDeserializer.<init>(CaseClassDeserializer.scala:18)
    at com.codahale.jerkson.deser.ScalaDeserializers.findBeanDeserializer(ScalaDeserializers.scala:94)
    at org.codehaus.jackson.map.deser.BeanDeserializerFactory._findCustomBeanDeserializer(BeanDeserializerFactory.java:278)
    at org.codehaus.jackson.map.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:315)
    at org.codehaus.jackson.map.deser.StdDeserializerProvider._createDeserializer(StdDeserializerProvider.java:364)
    at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCache2(StdDeserializerProvider.java:286)
    at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCacheValueDeserializer(StdDeserializerProvider.java:266)
    at org.codehaus.jackson.map.deser.StdDeserializerProvider.findValueDeserializer(StdDeserializerProvider.java:124)
    at org.codehaus.jackson.map.deser.StdDeserializerProvider.findTypedValueDeserializer(StdDeserializerProvider.java:145)
    at org.codehaus.jackson.map.ObjectMapper._findRootDeserializer(ObjectMapper.java:2195)
    at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2110)
    at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1002)
    at com.codahale.jerkson.Parser$class.parse(Parser.scala:72)
    at com.codahale.jerkson.Json$.parse(Json.scala:6)
    at com.codahale.jerkson.Parser$class.parse(Parser.scala:14)
    at com.codahale.jerkson.Json$.parse(Json.scala:6)
    at .<init>(<console>:13)
    at .<clinit>(<console>)
    at .<init>(<console>:11)
    at .<clinit>(<console>)
    at $export(<console>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:592)
    at scala.tools.nsc.interpreter.IMain$Request$$anonfun$10.apply(IMain.scala:828)
    at scala.tools.nsc.interpreter.Line$$anonfun$1.apply$mcV$sp(Line.scala:43)
    at scala.tools.nsc.io.package$$anon$2.run(package.scala:31)
    at java.lang.Thread.run(Thread.java:662)

Am I doing something wrong? Is the readme dated?

Thanks,

Leif

Support for Tuples?

Right now, Tuples are not supported by Jerkson, though it seems like they could easily be added. Your CaseClassSerializer/Deserializer classes are remarkably close to what is needed.

CaseClassSigParser#loadClass fails for external jars (Maven vs IDE)

My stuff works fine in IDE, but when running from Maven, my tests fail:

 [main] ERROR c.s.j.s.container.ContainerResponse       - The exception contained within MappableContainerException could not be mapped to a response, re-throwing to the HTTP container
  java.lang.ClassNotFoundException: com.foo.bar.Bottle
  at java.net.URLClassLoader$1.run(URLClassLoader.java:202) ~[na:1.6.0_26]
  at java.security.AccessController.doPrivileged(Native Method) ~[na:1.6.0_26]
  at java.net.URLClassLoader.findClass(URLClassLoader.java:190) ~[na:1.6.0_26]
  at java.lang.ClassLoader.loadClass(ClassLoader.java:306) ~[na:1.6.0_26]
  at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) ~[na:1.6.0_26]
  at java.lang.ClassLoader.loadClass(ClassLoader.java:247) ~[na:1.6.0_26]
  at com.codahale.jerkson.util.CaseClassSigParser$.loadClass(CaseClassSigParser.scala:135) ~[jerkson_2.9.1-0.4.2.jar:na]
  at com.codahale.jerkson.util.CaseClassSigParser$.findRootClass(CaseClassSigParser.scala:49) ~[jerkson_2.9.1-0.4.2.jar:na]
  at com.codahale.jerkson.util.CaseClassSigParser$.parseScalaSig(CaseClassSigParser.scala:42) ~[jerkson_2.9.1-0.4.2.jar:na]
  at com.codahale.jerkson.util.CaseClassSigParser$.findSym(CaseClassSigParser.scala:56) ~[jerkson_2.9.1-0.4.2.jar:na]
  at com.codahale.jerkson.util.CaseClassSigParser$.parse(CaseClassSigParser.scala:83) ~[jerkson_2.9.1-0.4.2.jar:na]

Works fine in IDE (dependent jar containing the class is a part of the modular project). Class loading issue?
I can construct an instance of the class (Bottle) just fine at the beginning of the unit test.

Unable to find a case accessor exception in test driver

This might be related to issue #52, but I'm not sure thought.

I'm using sbt (sbt run) where the following code snippet works as expected (JSON from/to case class conversion works fine):

package net.janihur.jerksonex

import com.codahale.jerkson.Json.{generate,parse}

object Main {

  case class Request(request: String = "GET_ITEMS", 
                     requestId: Int = 123, 
                     categories: List[Int] = List())

  def main(args: Array[String]) {
    println("jerksonex starts")

    val req = Request()

    val json = generate(req)

    println("1: " + json)

    val req2 = parse[Request](json)

    println("2: " + req2.toString)

    println("jerksonex ends")
  }
}

But when I put the same code to a test driver (sbt test) I'll get an exception:

[info]   com.codahale.jerkson.ParsingException: Unable to find a case accessor for net.janihur.jerksonex.test.MainTest$Request
[info]   at com.codahale.jerkson.ParsingException$.apply(ParsingException.scala:17)
[info]   at com.codahale.jerkson.Parser$class.parse(Parser.scala:86)
[info]   at com.codahale.jerkson.Json$.parse(Json.scala:6)
[info]   at com.codahale.jerkson.Parser$class.parse(Parser.scala:14)
[info]   at com.codahale.jerkson.Json$.parse(Json.scala:6)

I'm using ScalaTest:

package net.janihur.jerksonex.test

import org.scalatest.FunSuite
import com.codahale.jerkson.Json.{generate,parse}

class MainTest extends FunSuite {

  case class Request(request: String = "GET_ITEMS", 
                     requestId: Int = 123, 
                     categories: List[Int] = List())

  test("foo") {
    val req = Request()

    val json = generate(req)

    info("1: " + json)

    val req2 = parse[Request](json)

    info("2: " + req2.toString)
  }
}

Serialization of None Incorrect When In Case Class

case class Foo(a: Option[String])
val json = generate(Foo(None))

In this code json is set to {} rather than {"a":null}.

It should be as simple as adding this code to CaseClassSerializer.scala:32:

else {
  json.writeFieldName(methodOpt.map {_.getName}.getOrElse(field.getName))
  provider.getNullValueSerializer.serialize(null, json, provider)
}

Improve concurrency

Figure out a way to make Jackson contend less:

qtp2078619350-199 id=199 state=BLOCKED
    - waiting to lock <0x51cf2096> (a org.codehaus.jackson.map.ser.SerializerCache)
     owned by qtp2078619350-63 id=63
    at org.codehaus.jackson.map.ser.SerializerCache.getReadOnlyLookupMap(SerializerCache.java:49)
    at org.codehaus.jackson.map.ser.StdSerializerProvider.<init>(StdSerializerProvider.java:208)
    at org.codehaus.jackson.map.ser.StdSerializerProvider.createInstance(StdSerializerProvider.java:217)
    at org.codehaus.jackson.map.ser.StdSerializerProvider.serializeValue(StdSerializerProvider.java:239)
    at org.codehaus.jackson.map.ObjectMapper.writeValue(ObjectMapper.java:1143)
    at org.codehaus.jackson.impl.JsonGeneratorBase.writeObject(JsonGeneratorBase.java:315)
    at com.codahale.jerkson.Generator$class.generate(Generator.scala:38)
    at com.codahale.jerkson.Generator$class.generate(Generator.scala:27)
    at com.codahale.jerkson.Json$.generate(Json.scala:6)

EitherDeserializer is "weird"

Currently, the deserializer assumes the value is a Left() and simply surrounds it with try {} catch { Right() }.

This goes against the common use of Either (as documented in the scaladocs):
Represents a value of one of two possible types (a disjoint union). The data constructors Left and Right represent the two possible values. The Either type is often used as an alternative to Option where Left represents failure (by convention) and Right is akin to Some.

The most common case is: Either[Throwable, T] so this deserializer is essentially backwards from the common case; however, I think it would be good to deserialize it using some kind of meta-data to ensure that you get the expected Left/Right.

Fields from superclass not considered

Given


object JacksonJsonDemo {

  def main(argv: Array[String]) {
    val bar = new Bar(age=10)
    bar.name = "Bar"
    println(generate(bar))
  }

}

case class Foo(var name:String = "Foo")
case class Bar(var age:Int = 0) extends Foo

I was expecting

{"name":"Bar", "age": 10}

The fields from the superclass are not included. This appears to be related to issue #4 (#4). Is this a bug or the design of the API?

HashMap's and StringBuilder's generate incorrectly

scala> generate(scala.collection.immutable.HashMap(1->2))
res61: String = {"1":2}

scala> generate(scala.collection.mutable.HashMap(1->2))
res62: String = [{"_1":1,"_2":2}]

scala> generate(scala.collection.mutable.LinkedHashMap(1->2))
res63: String = [{"_1":1,"_2":2}]

scala> generate("foo")
res32: String = "foo"

scala> generate(new scala.collection.mutable.StringBuilder("foo"))
res31: String = ["f","o","o"]

I'm also submitting a pull request containing a comprehensive set of tests for the scala-2.8.1 collections (http://www.scala-lang.org/docu/files/collections-api/collections_2.html), including the three above that fail.

class not found exceptions when parsing in sbt tasks

I noticed that jerkson will throw a class not found exception when case class parsing occurs within an sbt task.

package baz    

import com.codahale.jerkson.Json._

case class Foo(bar: String)

(TaskKey[Unit]("jerkson", "parse with jerkson")) <<= (streams) map { (out) => 
   out.log.info(parse[Foo]("""{"bar":"boom"}"""))
 }

The relevant stack trace will look something like

    java.lang.ClassNotFoundException: baz.Foo
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at com.codahale.jerkson.util.CaseClassSigParser$.loadClass(CaseClassSigParser.scala:135)
at com.codahale.jerkson.util.CaseClassSigParser$.findRootClass(CaseClassSigParser.scala:49)
at com.codahale.jerkson.util.CaseClassSigParser$.parseScalaSig(CaseClassSigParser.scala:42)
at com.codahale.jerkson.util.CaseClassSigParser$.findSym(CaseClassSigParser.scala:56)
at com.codahale.jerkson.util.CaseClassSigParser$.parse(CaseClassSigParser.scala:83)
at com.codahale.jerkson.deser.CaseClassDeserializer.<init>(CaseClassDeserializer.scala:20)
at com.codahale.jerkson.deser.ScalaDeserializers.findBeanDeserializer(ScalaDeserializers.scala:94)
at org.codehaus.jackson.map.deser.BeanDeserializerFactory._findCustomBeanDeserializer(BeanDeserializerFactory.java:391)
at org.codehaus.jackson.map.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:433)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createDeserializer(StdDeserializerProvider.java:398)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCache2(StdDeserializerProvider.java:307)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCacheValueDeserializer(StdDeserializerProvider.java:287)
at org.codehaus.jackson.map.deser.StdDeserializerProvider.findValueDeserializer(StdDeserializerProvider.java:136)
at org.codehaus.jackson.map.deser.StdDeserializerProvider.findTypedValueDeserializer(StdDeserializerProvider.java:157)
at org.codehaus.jackson.map.ObjectMapper._findRootDeserializer(ObjectMapper.java:2461)
at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2376)
at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1166)
at com.codahale.jerkson.Parser$class.parse(Parser.scala:81)
at com.codahale.jerkson.Json$.parse(Json.scala:6)
at com.codahale.jerkson.Parser$class.parse(Parser.scala:14)
at com.codahale.jerkson.Json$.parse(Json.scala:6)

Jerkson does not Deserialize Immutable Map with Locale Key

Version 0.6.0-SNAPSHOT

When using a Scala map with a non-String key, the deserialization fails, serialization works fine.
Jackson has a special MapKeyDeserializer. The expectation was, that jerkson can deserialize the same types.

To reproduce:

import java.util.Locale

case class MapCase (names: Map[Locale, String])

object TestApp extends App with Json {
val obj = MapCase(Map(Locale.US -> "foo", Locale.CANADA -> "bar"))
val jsonStr = generate(obj)
println(jsonStr)
val parsedObj = parseMapCase
println(parsedObj)

}

Stacktrace:
Exception in thread "main" com.codahale.jerkson.ParsingException: Can not construct instance of scala.collection.immutable.Map, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
at [Source: N/A; line: -1, column: -1]
at com.codahale.jerkson.ParsingException$.apply(ParsingException.scala:17)
at com.codahale.jerkson.Parser$class.parse(Parser.scala:87)
at TestApp$.parse(WatchlistHotelDetail.scala:24)
at com.codahale.jerkson.Parser$class.parse(Parser.scala:15)
at TestApp$.parse(WatchlistHotelDetail.scala:24)
at TestApp$delayedInit$body.apply(WatchlistHotelDetail.scala:28)
at scala.Function0$class.apply$mcV$sp(Function0.scala:34)
at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
at scala.App$$anonfun$main$1.apply(App.scala:60)
at scala.App$$anonfun$main$1.apply(App.scala:60)
at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
at scala.collection.immutable.List.foreach(List.scala:76)
at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:30)
at scala.App$class.main(App.scala:60)
at TestApp$.main(WatchlistHotelDetail.scala:24)
at TestApp.main(WatchlistHotelDetail.scala)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of scala.collection.immutable.Map, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
at [Source: N/A; line: -1, column: -1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:163)
at com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:613)
at com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:112)
at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:2552)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1386)
at com.codahale.jerkson.deser.CaseClassDeserializer.deserialize(CaseClassDeserializer.scala:58)
at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:2552)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1386)
at com.codahale.jerkson.Parser$class.parse(Parser.scala:84)
... 14 more

Cannot un-marshal case classes when encountering an empty Map

import com.codahale.simplespec.Spec
import com.codahale.jerkson.Json
import java.io.{StringWriter, StringReader}

case class PayloadConfiguration(networkId: Int, simulation: Boolean, thresholds: Map[String,Double])

object PayloadConfigurationSpec extends Spec {

  class `payload configuration` {

    def `should be idempotent wrt jerkson with an empty map`() {
      val configuration = PayloadConfiguration(1, true, Map[String,Double]())
      val writer = new StringWriter
      Json.generate(configuration, writer)
      val parsed = Json.parse[PayloadConfiguration](new StringReader(writer.toString))
      parsed must beEqualTo(configuration)
    }

    def `should be idempotent wrt jerkson with a non-empty map`() {
      val configuration = PayloadConfiguration(1, true, Map[String,Double]("a" -> 1.0))
      val writer = new StringWriter
      Json.generate(configuration, writer)
      val parsed = Json.parse[PayloadConfiguration](new StringReader(writer.toString))
      parsed must beEqualTo(configuration)
    }

  }

}

/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/bin/java -Dfile.encoding=UTF-8 -classpath /Users/cvandyck/code/syncie/target/scala_2.8.1/test-resources:/Users/cvandyck/code/syncie/target/scala_2.8.1/resources:/System/Library/Java/Support/Deploy.bundle/Contents/Resources/Java/deploy.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/dt.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/javaws.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/jce.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/jconsole.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/management-agent.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/plugin.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/sa-jdi.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/alt-rt.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/charsets.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/classes.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/jsse.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Classes/ui.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/ext/apple_provider.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/ext/dnsns.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/ext/localedata.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/ext/sunjce_provider.jar:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/ext/sunpkcs11.jar:/Users/cvandyck/code/syncie/target/scala_2.8.1/test-classes:/Users/cvandyck/code/syncie/target/scala_2.8.1/classes:/Users/cvandyck/code/syncie/project/boot/scala-2.8.1/lib/scala-compiler.jar:/Users/cvandyck/code/syncie/project/boot/scala-2.8.1/lib/scala-library.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/jetty-continuation-7.3.1.v20110307.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/hornetq-core-client-2.1.2.Final.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/jetty-server-7.3.1.v20110307.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/jetty-servlets-7.3.1.v20110307.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/jetty-io-7.3.1.v20110307.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/jersey-core-1.5.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/test/simplespec_2.8.1-0.2.0.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/guice-2.0.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/test/mockito-all-1.8.5.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/commons-pool-1.5.4.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/jul-to-slf4j-1.6.1.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/jerkson_2.8.1-0.1.6.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/jetty-security-7.3.1.v20110307.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/jackson-mapper-asl-1.7.1.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/jersey-guice-1.5.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/netty-3.2.0.Final.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/logula_2.8.1-2.1.0.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/test/specs_2.8.1-1.6.6.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/paranamer-2.3.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/servlet-api-2.5.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/test/specs_2.8.0-1.6.5.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/slf4j-api-1.6.1.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/jackson-core-asl-1.7.3.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/log4j-1.2.16.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/guice-servlet-2.0.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/jersey-scala_2.8.1-0.1.2.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/hornetq-bootstrap-2.1.2.Final.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/jersey-server-1.5.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/hornetq-core-2.1.2.Final.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/jetty-http-7.3.1.v20110307.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/metrics_2.8.1-2.0.0-BETA10.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/fig_2.8.1-1.1.1.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/commons-cli-1.2.jar:/Users/cvandyck/code/syncie/lib/zookeeper-3.3.3.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/commons-lang-2.5.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/easy-process_2.8.1-1.0-SNAPSHOT.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/jetty-client-7.3.1.v20110307.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/jetty-util-7.3.1.v20110307.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/aopalliance-1.0.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/commons-codec-1.2.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/guice-multibindings-2.0.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/asm-3.1.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/embedded-hornet_2.8.1-1.0.9.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/jetty-servlet-7.3.1.v20110307.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/dropwizard_2.8.1-0.0.2.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/scala-utils_2.8.1-0.1.3-SNAPSHOT.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/slf4j-log4j12-1.6.1.jar:/Users/cvandyck/code/syncie/lib_managed/scala_2.8.1/compile/commons-io-2.0.1.jar com.yammer.syncie.job.PayloadConfigurationSpec
Specification "PayloadConfigurationSpec"
  payload configuration should
  x  be idempotent wrt jerkson with an empty map
    com.codahale.jerkson.ParsingException: Invalid JSON. (ParsingException.scala:23)
    at com.codahale.jerkson.ParsingException$.apply(ParsingException.scala:23)
    at com.codahale.jerkson.Parser$class.parse(Parser.scala:84)
    at com.codahale.jerkson.Json$.parse(Json.scala:6)
    at com.codahale.jerkson.Parser$class.parse(Parser.scala:34)
    at com.codahale.jerkson.Json$.parse(Json.scala:6)
    at com.yammer.syncie.job.PayloadConfigurationSpec$payload$u0020configuration.should$u0020be$u0020idempotent$u0020wrt$u0020jerkson$u0020with$u0020an$u0020empty$u0020map(PayloadConfigurationSpec.scala:15)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.codahale.simplespec.Spec$$anonfun$2$$anonfun$apply$1$$anonfun$apply$mcV$sp$4$$anonfun$apply$2.apply(Spec.scala:40)
    at org.specs.specification.LifeCycle$class.withCurrent(ExampleLifeCycle.scala:60)
    at org.specs.specification.Examples.withCurrent(Examples.scala:52)
    at org.specs.specification.Examples$$anonfun$specifyExample$1.apply(Examples.scala:111)
    at org.specs.specification.Examples$$anonfun$specifyExample$1.apply(Examples.scala:111)
    at org.specs.specification.ExampleExecution$$anonfun$3$$anonfun$apply$5.apply(ExampleLifeCycle.scala:213)
    at scala.Option.getOrElse(Option.scala:104)
    at org.specs.specification.LifeCycle$class.executeExpectations(ExampleLifeCycle.scala:84)
    at org.specs.specification.BaseSpecification.executeExpectations(BaseSpecification.scala:58)
    at org.specs.specification.ExampleContext$$anonfun$executeExpectations$3$$anonfun$apply$3$$anonfun$apply$4.apply(ExampleContext.scala:81)
    at org.specs.specification.ExampleContext$$anonfun$executeExpectations$3$$anonfun$apply$3$$anonfun$apply$4.apply(ExampleContext.scala:81)
    at scala.Option.map(Option.scala:129)
    at org.specs.specification.ExampleContext$$anonfun$executeExpectations$3$$anonfun$apply$3.apply(ExampleContext.scala:81)
    at org.specs.specification.ExampleContext$$anonfun$executeExpectations$3$$anonfun$apply$3.apply(ExampleContext.scala:81)
    at org.specs.specification.ExampleContext$class.id$1(ExampleContext.scala:32)
    at org.specs.specification.ExampleContext$$anonfun$1.apply(ExampleContext.scala:33)
    at org.specs.specification.ExampleContext$$anonfun$1.apply(ExampleContext.scala:33)
    at org.specs.specification.ExampleContext$$anonfun$executeExpectations$3.apply(ExampleContext.scala:81)
    at org.specs.specification.ExampleContext$$anonfun$executeExpectations$3.apply(ExampleContext.scala:80)
    at scala.Option.map(Option.scala:129)
    at org.specs.specification.ExampleContext$class.executeExpectations(ExampleContext.scala:80)
    at org.specs.specification.Examples.executeExpectations(Examples.scala:52)
    at org.specs.specification.ExampleContext$$anonfun$executeExpectations$3$$anonfun$apply$3$$anonfun$apply$4.apply(ExampleContext.scala:81)
    at org.specs.specification.ExampleContext$$anonfun$executeExpectations$3$$anonfun$apply$3$$anonfun$apply$4.apply(ExampleContext.scala:81)
    at scala.Option.map(Option.scala:129)
    at org.specs.specification.ExampleContext$$anonfun$executeExpectations$3$$anonfun$apply$3.apply(ExampleContext.scala:81)
    at org.specs.specification.ExampleContext$$anonfun$executeExpectations$3$$anonfun$apply$3.apply(ExampleContext.scala:81)
    at org.specs.specification.ExampleContext$class.id$1(ExampleContext.scala:32)
    at org.specs.specification.ExampleContext$$anonfun$1.apply(ExampleContext.scala:33)
    at org.specs.specification.ExampleContext$$anonfun$1.apply(ExampleContext.scala:33)
    at org.specs.specification.ExampleContext$$anonfun$executeExpectations$3.apply(ExampleContext.scala:81)
    at org.specs.specification.ExampleContext$$anonfun$executeExpectations$3.apply(ExampleContext.scala:80)
    at scala.Option.map(Option.scala:129)
    at org.specs.specification.ExampleContext$class.executeExpectations(ExampleContext.scala:80)
    at org.specs.specification.Examples.executeExpectations(Examples.scala:52)
    at org.specs.specification.ExampleExecution$$anonfun$3.apply(ExampleLifeCycle.scala:213)
    at org.specs.specification.ExampleExecution$$anonfun$3.apply(ExampleLifeCycle.scala:192)
    at org.specs.specification.ExampleExecution$$anonfun$2.apply(ExampleLifeCycle.scala:175)
    at org.specs.specification.ExampleExecution.execute(ExampleLifeCycle.scala:246)
    at org.specs.specification.SpecificationExecutor$$anonfun$executeExample$3.apply(SpecificationExecutor.scala:70)
    at org.specs.specification.SpecificationExecutor$$anonfun$executeExample$3.apply(SpecificationExecutor.scala:70)
    at scala.Option.map(Option.scala:129)
    at org.specs.specification.SpecificationExecutor$class.executeExample(SpecificationExecutor.scala:70)
    at org.specs.specification.BaseSpecification.executeExample(BaseSpecification.scala:58)
    at org.specs.specification.BaseSpecification.executeExample(BaseSpecification.scala:58)
    at org.specs.specification.ExampleLifeCycle$$anonfun$executeExample$1.apply(ExampleLifeCycle.scala:119)
    at org.specs.specification.ExampleLifeCycle$$anonfun$executeExample$1.apply(ExampleLifeCycle.scala:119)
    at scala.Option.map(Option.scala:129)
    at org.specs.specification.ExampleLifeCycle$class.executeExample(ExampleLifeCycle.scala:119)
    at org.specs.specification.Examples.executeExample(Examples.scala:52)
    at org.specs.specification.Examples.executeExample(Examples.scala:52)
    at org.specs.specification.Examples$$anonfun$executeExamples$1.apply(Examples.scala:80)
    at org.specs.specification.Examples$$anonfun$executeExamples$1.apply(Examples.scala:80)
    at scala.Option.map(Option.scala:129)
    at org.specs.specification.Examples.executeExamples(Examples.scala:80)
    at org.specs.specification.ExampleStructure$class.ownFailures(ExampleStructure.scala:58)
    at org.specs.specification.Examples.ownFailures(Examples.scala:52)
    at org.specs.specification.ExampleStructure$class.failures(ExampleStructure.scala:64)
    at org.specs.specification.Examples.failures(Examples.scala:52)
    at org.specs.specification.Examples.failures(Examples.scala:52)
    at org.specs.execute.HasResults$class.failureAndErrors(HasResults.scala:61)
    at org.specs.specification.Examples.failureAndErrors(Examples.scala:52)
    at org.specs.execute.HasResults$class.hasFailureOrErrors(HasResults.scala:59)
    at org.specs.specification.Examples.hasFailureOrErrors(Examples.scala:52)
    at org.specs.runner.OutputReporter$class.status$1(ConsoleReporter.scala:223)
    at org.specs.runner.OutputReporter$class.reportExample(ConsoleReporter.scala:232)
    at org.specs.Specification.reportExample(Specification.scala:43)
    at org.specs.runner.OutputReporter$$anonfun$reportExamples$1.apply(ConsoleReporter.scala:210)
    at org.specs.runner.OutputReporter$$anonfun$reportExamples$1.apply(ConsoleReporter.scala:209)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:61)
    at scala.collection.immutable.List.foreach(List.scala:45)
    at org.specs.runner.OutputReporter$class.reportExamples(ConsoleReporter.scala:209)
    at org.specs.Specification.reportExamples(Specification.scala:43)
    at org.specs.runner.OutputReporter$class.printSus(ConsoleReporter.scala:174)
    at org.specs.Specification.printSus(Specification.scala:43)
    at org.specs.runner.OutputReporter$class.displaySus$1(ConsoleReporter.scala:141)
    at org.specs.runner.OutputReporter$$anonfun$reportSystems$1.apply(ConsoleReporter.scala:147)
    at org.specs.runner.OutputReporter$$anonfun$reportSystems$1.apply(ConsoleReporter.scala:142)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:61)
    at scala.collection.immutable.List.foreach(List.scala:45)
    at org.specs.runner.OutputReporter$class.reportSystems(ConsoleReporter.scala:142)
    at org.specs.Specification.reportSystems(Specification.scala:43)
    at org.specs.runner.OutputReporter$class.reportSpec(ConsoleReporter.scala:87)
    at org.specs.Specification.reportSpec(Specification.scala:43)
    at org.specs.runner.OutputReporter$$anonfun$report$1.apply(ConsoleReporter.scala:74)
    at org.specs.runner.OutputReporter$$anonfun$report$1.apply(ConsoleReporter.scala:74)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:61)
    at scala.collection.immutable.List.foreach(List.scala:45)
    at org.specs.runner.OutputReporter$class.report(ConsoleReporter.scala:74)
    at org.specs.Specification.report(Specification.scala:43)
    at org.specs.runner.OutputReporter$class.report(ConsoleReporter.scala:65)
    at org.specs.Specification.report(Specification.scala:43)
    at org.specs.Specification.report(Specification.scala:43)
    at org.specs.runner.Reporter$class.reportSpecs(Reporter.scala:195)
    at org.specs.Specification.reportSpecs(Specification.scala:43)
    at org.specs.runner.Reporter$class.main(Reporter.scala:140)
    at org.specs.Specification.main(Specification.scala:43)
    at com.yammer.syncie.job.PayloadConfigurationSpec.main(PayloadConfigurationSpec.scala)
Caused by: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.lang.Double out of END_OBJECT token
 at [Source: N/A; line: -1, column: -1]
    at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:160)
    at org.codehaus.jackson.map.deser.StdDeserializationContext.mappingException(StdDeserializationContext.java:198)
    at com.codahale.jerkson.deser.MapDeserializer.deserialize(MapDeserializer.scala:24)
    at com.codahale.jerkson.deser.MapDeserializer.deserialize(MapDeserializer.scala:11)
    at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2112)
    at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1004)
    at com.codahale.jerkson.deser.CaseClassDeserializer$$anonfun$deserialize$1$$anonfun$apply$1.apply(CaseClassDeserializer.scala:49)
    at com.codahale.jerkson.deser.CaseClassDeserializer$$anonfun$deserialize$1$$anonfun$apply$1.apply(CaseClassDeserializer.scala:41)
    at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:57)
    at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:43)
    at com.codahale.jerkson.deser.CaseClassDeserializer$$anonfun$deserialize$1.apply(CaseClassDeserializer.scala:41)
    at com.codahale.jerkson.deser.CaseClassDeserializer$$anonfun$deserialize$1.apply(CaseClassDeserializer.scala:39)
    at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:34)
    at scala.collection.mutable.WrappedArray.foreach(WrappedArray.scala:32)
    at com.codahale.jerkson.deser.CaseClassDeserializer.deserialize(CaseClassDeserializer.scala:39)
    at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2112)
    at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1004)
    at com.codahale.jerkson.Parser$class.parse(Parser.scala:81)
    ... 106 more
  +  be idempotent wrt jerkson with a non-empty map

Total for specification "PayloadConfigurationSpec":
Finished in 0 second, 512 ms
2 examples, 1 expectation, 0 failure, 1 error

Add instructions for SBT installation

You might want to mention in the README how to include Jerkson in an SBT based project:

In the root SBT project directory, create/edit the build.sbt file to contain the following two lines,

resolvers ++= Seq("Codahale" at "http://repo.codahale.com")

libraryDependencies ++= Seq("com.codahale" %% "jerkson" % "0.5.0")

Note that they must be separated by an empty line.

Parsing of case class with Strings starting with "{" fails

There is a valid scenario where a String may start with "{" when parsing a case class but I get the following exception because it decides that it must be an Object:

com.codahale.jerkson.ParsingException: Can not deserialize instance of java.lang.String out of START_OBJECT token

The defined type being String should tell the parser to ignore the type and simply put the data into the String.

Is there an annotation or something I can supply to my case class to tell Jerkson to just push the value in without trying to parse it?

Example:

case class Test(name: String)

parse[Test]("""{ "name": "{hello}" }""") <-- will throw an exception because it starts with "{"

ClassNotFoundException when parsing in sbt test

When I run this spec with sbt test:

case class Child(id: Int)
case class Parent(child: Child)

class FooSpecs extends Specification {
  var bar = parse[Parent]("""{"child":{"id":1}}""")

  // some tests...

}

I get ClassNotFoundException:

java.lang.ClassNotFoundException: <empty>.Child
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    at com.codahale.jerkson.util.CaseClassSigParser$.loadClass(CaseClassSigParser.scala:153)
    at com.codahale.jerkson.util.CaseClassSigParser$.typeRef2JavaType(CaseClassSigParser.scala:111)
    at com.codahale.jerkson.util.CaseClassSigParser$$anonfun$parse$2.apply(CaseClassSigParser.scala:86)
    at com.codahale.jerkson.util.CaseClassSigParser$$anonfun$parse$2.apply(CaseClassSigParser.scala:84)
    at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:200)
    at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:200)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
    at scala.collection.immutable.List.foreach(List.scala:45)
    at scala.collection.TraversableLike$class.flatMap(TraversableLike.scala:200)
    at scala.collection.immutable.List.flatMap(List.scala:45)
    at com.codahale.jerkson.util.CaseClassSigParser$.parse(CaseClassSigParser.scala:84)
    at com.codahale.jerkson.deser.CaseClassDeserializer.<init>(CaseClassDeserializer.scala:20)
    at com.codahale.jerkson.deser.ScalaDeserializers.findBeanDeserializer(ScalaDeserializers.scala:94)
    at org.codehaus.jackson.map.deser.BeanDeserializerFactory._findCustomBeanDeserializer(BeanDeserializerFactory.java:482)
    at org.codehaus.jackson.map.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:599)
    at org.codehaus.jackson.map.deser.StdDeserializerProvider._createDeserializer(StdDeserializerProvider.java:401)
    at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCache2(StdDeserializerProvider.java:310)
    at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCacheValueDeserializer(StdDeserializerProvider.java:290)
    at org.codehaus.jackson.map.deser.StdDeserializerProvider.findValueDeserializer(StdDeserializerProvider.java:159)
    at org.codehaus.jackson.map.deser.StdDeserializerProvider.findTypedValueDeserializer(StdDeserializerProvider.java:180)
    at org.codehaus.jackson.map.ObjectMapper._findRootDeserializer(ObjectMapper.java:2829)
    at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2699)
    at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1315)
    at com.codahale.jerkson.Parser$class.parse(Parser.scala:83)
    at com.codahale.jerkson.Json$.parse(Json.scala:6)
    at com.codahale.jerkson.Parser$class.parse(Parser.scala:14)
    at com.codahale.jerkson.Json$.parse(Json.scala:6)
    at FooSpecs.<init>(hoge.scala:8)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at org.specs2.reflect.Classes$class.createInstanceFor(Classes.scala:98)
    at org.specs2.reflect.Classes$.createInstanceFor(Classes.scala:130)
    at org.specs2.reflect.Classes$$anonfun$create$1.apply(Classes.scala:19)
    at org.specs2.control.Exceptions$class.trye(Exceptions.scala:82)
    at org.specs2.control.Exceptions$.trye(Exceptions.scala:98)
    at org.specs2.reflect.Classes$class.create(Classes.scala:19)
    at org.specs2.reflect.Classes$.create(Classes.scala:130)
    at org.specs2.runner.TestInterfaceRunner.toRun(TestInterfaceRunner.scala:69)
    at org.specs2.runner.TestInterfaceRunner.runSpecification(TestInterfaceRunner.scala:58)
    at org.specs2.runner.TestInterfaceRunner.run(TestInterfaceRunner.scala:54)
    at sbt.TestRunner.delegateRun(TestFramework.scala:61)
    at sbt.TestRunner.run(TestFramework.scala:55)
    at sbt.TestRunner.runTest$1(TestFramework.scala:75)
    at sbt.TestRunner.run(TestFramework.scala:84)
    at sbt.TestFramework$$anonfun$6$$anonfun$apply$8$$anonfun$7$$anonfun$apply$9.apply(TestFramework.scala:183)
    at sbt.TestFramework$$anonfun$6$$anonfun$apply$8$$anonfun$7$$anonfun$apply$9.apply(TestFramework.scala:183)
    at sbt.TestFramework$.sbt$TestFramework$$withContextLoader(TestFramework.scala:195)
    at sbt.TestFramework$$anonfun$6$$anonfun$apply$8$$anonfun$7.apply(TestFramework.scala:183)
    at sbt.TestFramework$$anonfun$6$$anonfun$apply$8$$anonfun$7.apply(TestFramework.scala:183)
    at sbt.Tests$$anonfun$makeParallel$1$$anonfun$apply$7.apply(Tests.scala:113)
    at sbt.Tests$$anonfun$makeParallel$1$$anonfun$apply$7.apply(Tests.scala:113)
    at sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:47)
    at sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:47)
    at sbt.std.Transform$$anon$5.work(System.scala:67)
    at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:221)
    at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:221)
    at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:18)
    at sbt.Execute.work(Execute.scala:227)
    at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:221)
    at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:221)
    at sbt.CompletionService$$anon$1$$anon$2.call(CompletionService.scala:26)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:680)

But when I do the exactly same on sbt console like this:

scala> import com.codahale.jerkson.Json._
import com.codahale.jerkson.Json._

scala> import com.foo.bar._
import com.foo.bar._ // This contains Parent and Child class

scala> parse[Parent]("""{"child":{"id":1}}""")
res1: com.foo.bar.Parent = Parent(Child(1))

It just works! I don't know why this doesn't fail in sbt console and it does in sbt test. I've tried @softprops' solution described on #38 but still no luck. The version of Scala is 2.9.1 and sbt is 0.11.2. Any advice/solutions?

How to work with jerkson and other jackson modules

We have a de/serializer for BSON ObjectId's registered like this:

val mapper = new ObjectMapper
val module: SimpleModule = new SimpleModule("foo", Version.unknownVersion())
module.addSerializer(classOf[ObjectId], new ObjectIdSerializer)
module.addDeserializer(classOf[ObjectId], new ObjectIdDeserializer)
mapper.registerModule(module)

But it does not seem to be picked up when serializing a case class that has an ObjectId using generate. Could it be that for this to work, the de/serializers need to be registered against the same ObjectMapper than the one jerkson uses? If yes, how to get a hold on them?

Thanks,

manuel

Make auto-close optional

When a writer is supplied to Jerkson, it passes it off to Jackson generator configured to auto-close the supplied writer. It would be nice to be able to turn that off. When I'm working with a very large JSON file parsing it via the Jackson streaming API, it's expensive to open up a writer each time I need to write data to a particular file. To get around this, I am currently:

val sw = new StringWriter
Json.parse(obj, sw)
val writer = getCachedWriter(file)
writer.write(sw.toString)
writer.flush

Jerkson Fails on Case Classes that Contain a Map

The following code snippet works just fine:

parse[Map[Int, Int]](generate(Map(1 -> 2)))

The following, however, doesn't, despite it seemingly being a fairly trivial extension of the above:

case class Foo(a: Map[Int, Int])
parse[Foo](generate(Foo(Map(1 -> 2))))

This yields the following exception:

com.codahale.jerkson.ParsingException: Can not construct instance of scala.collection.immutable.Map, problem: abstract types can only be instantiated with additional type information
 at [Source: N/A; line: -1, column: -1]
    at com.codahale.jerkson.ParsingException$.apply(ParsingException.scala:17)
    at com.codahale.jerkson.Parser$class.parse(Parser.scala:75)
    at com.codahale.jerkson.Json$.parse(Json.scala:6)
    at com.codahale.jerkson.Parser$class.parse(Parser.scala:14)
    at com.codahale.jerkson.Json$.parse(Json.scala:6)
    at .<init>(<console>:12)
    at .<clinit>(<console>)
    at .<init>(<console>:11)
    at .<clinit>(<console>)
    at $export(<console>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:592)
    at scala.tools.nsc.interpreter.IMain$Request$$anonfun$10.apply(IMain.scala:828)
    at scala.tools.nsc.interpreter.Line$$anonfun$1.apply$mcV$sp(Line.scala:43)
    at scala.tools.nsc.io.package$$anon$2.run(package.scala:31)
    at java.lang.Thread.run(Thread.java:680)
Caused by: org.codehaus.jackson.map.JsonMappingException: Can not construct instance of scala.collection.immutable.Map, problem: abstract types can only be instantiated with additional type information
 at [Source: N/A; line: -1, column: -1]
    at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:163)
    at org.codehaus.jackson.map.deser.StdDeserializationContext.instantiationException(StdDeserializationContext.java:212)
    at org.codehaus.jackson.map.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:97)
    at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2372)
    at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1162)
    at com.codahale.jerkson.deser.CaseClassDeserializer$$anonfun$deserialize$2.apply(CaseClassDeserializer.scala:40)
    at com.codahale.jerkson.deser.CaseClassDeserializer$$anonfun$deserialize$2.apply(CaseClassDeserializer.scala:33)
    at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:34)
    at scala.collection.mutable.ArrayOps.foreach(ArrayOps.scala:38)
    at com.codahale.jerkson.deser.CaseClassDeserializer.deserialize(CaseClassDeserializer.scala:33)
    at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2372)
    at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1162)
    at com.codahale.jerkson.Parser$class.parse(Parser.scala:72)
    ... 17 more

Parsing fails for Maps that contain unmarshalled keys

The following code snippets works just fine:

import java.net.URL
parse[Map[String,URL]](generate(Map(new URL("http://foo.com") -> new URL("http://foo.com"))))
//res: Map[String,java.net.URL] = Map(http://foo.com -> http://foo.com)

But the following:

import java.net.URL
parse[Map[URL,URL]](generate(Map(new URL("http://foo.com") -> new URL("http://foo.com"))))

throws

org.codehaus.jackson.map.JsonMappingException: Can not construct instance of scala.collection.immutable.Map, problem: abstract types can only be instantiated with additional type information
 at [Source: java.io.StringReader@1a47da2e; line: 1, column: 1]
    at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:163)
    at     org.codehaus.jackson.map.deser.StdDeserializationContext.instantiationException(StdDeserializationContext.java:233)
    at org.codehaus.jackson.map.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:60)
    at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2704)
    at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1315)
    at com.codahale.jerkson.Parser$class.parse(Parser.scala:83)
    ... 35 more

and I can't figure out how to proceed...

P.S. Thanks for a basically awesome library!

Can't parse case class with type-alias field

import com.codahale.jerkson.Json

object A {

  type Z = Int
  case class Ok(x: Int)
  case class Bad(x: Z)

  def main(args: Array[String]) {
    println(Json.parse[Ok]("""{"x":3}"""))
    println(Json.parse[Bad]("""{"x":3}""")) // ERROR: java.lang.ClassNotFoundException: Z
  }

}

Optional _typeHint generation

Idea shameless stolen from the Salat project... it would be cool to have a switch to optionally turn on generation of a _typeHint parameter in the generated Json, and have deserializer use the hint.

You could have something like this:

trait Stuff
case class Car extends Stuff
case class Truck extends Stuff
case class Train( val numCars:Int) extends Stuff
case class MyStuff( val name:String, val favorites:List[Stuff])

val ms = MyStuff("Greg", List(Car(), Train(5))

Currently I'm not sure how Jerkson would know what to do with this. It might generate something like this:

{"name":"Greg","favorites":[{},{"numCars":5}]}

Ok, but how would it deserialize this? It has no way to know that {} is actually a Car object...or is it a Truck object?

Salat's _typeHint solves this by generating something like:

{"_typeHint":"MyStuff","name":"Greg","favorites":[{"_typeHint":"Car"},{"_typeHint":"Train","numCars":5}]}

If you've got something in the deserializer to catch and read the type hint you know exactly what kind of object to create.

Of course this would be some kind of config parameter so you wouldn't get the hints unless you wanted them.

Omit null values

Currently i have a case class that has an option parameter default to null:
Element(author:String, image:Option[ImageElement]=None)

When using generateElement, it will output """ {"author":"foobar", "image":null} """, is it possible to omit printing the KV pair if the value is null so that only {"author":"foobar"} would be printed?

Huge List of Exceptions on generate()

I'm having this code:

import play.api.Play.current
import java.util.{Date}
import play.api.libs.json._
import com.codahale.jerkson.Json._

case class Profile(id: String,
                   displayName: Option[String] = None,
                   public: Boolean = false,
                   nsfw: Boolean = false,
                   created: Date = new Date,
                   meta: Map[String, String] = Map.empty) {
    lazy val asJson = generate(this)
}

When I try to evaluate the asJson, I get a load of exceptions, and +2GB of RAM usage. The list so long that I can't get the beginning because the console logs are cut off. Here is a snippet from the beginning, they're the same over and over:


java.lang.reflect.InvocationTargetException: null
    at sun.reflect.GeneratedMethodAccessor15.invoke(Unknown Source) ~[na:na]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_03]
    at java.lang.reflect.Method.invoke(Method.java:601) ~[na:1.7.0_03]
    at com.codahale.jerkson.ser.CaseClassSerializer.serialize(CaseClassSerializer.scala:33) ~[jerkson_2.9.1-0.5.0.jar:na]
    at com.codahale.jerkson.ser.CaseClassSerializer.serialize(CaseClassSerializer.scala:12) ~[jerkson_2.9.1-0.5.0.jar:na]
    at org.codehaus.jackson.map.ser.StdSerializerProvider._serializeValue(StdSerializerProvider.java:610) ~[jackson-mapper-asl-1.9.6.jar:1.9.6]
org.codehaus.jackson.map.JsonMappingException: [no message for java.lang.reflect.InvocationTargetException]
    at org.codehaus.jackson.map.ser.StdSerializerProvider._serializeValue(StdSerializerProvider.java:625) ~[jackson-mapper-asl-1.9.6.jar:1.9.6]
    at org.codehaus.jackson.map.ser.StdSerializerProvider.serializeValue(StdSerializerProvider.java:256) ~[jackson-mapper-asl-1.9.6.jar:1.9.6]
    at org.codehaus.jackson.map.ObjectMapper.writeValue(ObjectMapper.java:1613) ~[jackson-mapper-asl-1.9.6.jar:1.9.6]
    at org.codehaus.jackson.impl.JsonGeneratorBase.writeObject(JsonGeneratorBase.java:314) ~[jackson-core-asl-1.9.6.jar:1.9.6]
    at com.codahale.jerkson.Generator$class.generate(Generator.scala:43) ~[jerkson_2.9.1-0.5.0.jar:na]
    at com.codahale.jerkson.Generator$class.generate(Generator.scala:20) ~[jerkson_2.9.1-0.5.0.jar:na]

This also persists when I remove the Map field, so it's not linked to that other issue.

NullPointerException in corner case of erroneous parsing

Raises a NullPointerException when trying to parse "[{}]" as a Map[String, Any]:

scala> com.codahale.jerkson.Json.parse[Map[String, Any]]("[{}]")
java.lang.NullPointerException
        at org.codehaus.jackson.map.deser.UntypedObjectDeserializer.deserialize(UntypedObjectDeserializer.java:36)
        at com.codahale.jerkson.deser.ImmutableMapDeserializer.deserialize(ImmutableMapDeserializer.scala:26)
        at com.codahale.jerkson.deser.ImmutableMapDeserializer.deserialize(ImmutableMapDeserializer.scala:11)
        at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2110)
        at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1002)
        at com.codahale.jerkson.Parser$class.parse(Parser.scala:81)
        at com.codahale.jerkson.Json$.parse(Json.scala:6)
        at com.codahale.jerkson.Parser$class.parse(Parser.scala:14)
        at com.codahale.jerkson.Json$.parse(Json.scala:6)
        at .<init>(<console>:8)
        at .<clinit>(<console>)
        at .<init>(<console>:11)
        at .<clinit>(<console>)
        at $export(<console>)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:592)
        at scala.tools.nsc.interpreter.IMain$Request$$anonfun$10.apply(IMain.scala:828)
        at scala.tools.nsc.interpreter.Line$$anonfun$1.apply$mcV$sp(Line.scala:43)
        at scala.tools.nsc.io.package$$anon$2.run(package.scala:31)
        at java.lang.Thread.run(Thread.java:680)

Correctly raises a ParsingException when trying to parse Map[String, Int]:

scala> com.codahale.jerkson.Json.parse[Map[String, Int]]("[{}]")
com.codahale.jerkson.ParsingException: Can not deserialize instance of int out of START_OBJECT token
 at [Source: java.io.StringReader@c089e41; line: 1, column: 2]
        at com.codahale.jerkson.ParsingException$.apply(ParsingException.scala:17)
        at com.codahale.jerkson.Parser$class.parse(Parser.scala:84)
        at com.codahale.jerkson.Json$.parse(Json.scala:6)
        at com.codahale.jerkson.Parser$class.parse(Parser.scala:14)
        at com.codahale.jerkson.Json$.parse(Json.scala:6)
        at .<init>(<console>:8)
        at .<clinit>(<console>)
        at .<init>(<console>:11)
        at .<clinit>(<console>)
        at $export(<console>)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:592)
        at scala.tools.nsc.interpreter.IMain$Request$$anonfun$10.apply(IMain.scala:828)
        at scala.tools.nsc.interpreter.Line$$anonfun$1.apply$mcV$sp(Line.scala:43)
        at scala.tools.nsc.io.package$$anon$2.run(package.scala:31)
        at java.lang.Thread.run(Thread.java:680)
Caused by: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of int out of START_OBJECT token
 at [Source: java.io.StringReader@c089e41; line: 1, column: 2]
        at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:163)
        at org.codehaus.jackson.map.deser.StdDeserializationContext.mappingException(StdDeserializationContext.java:198)
        at org.codehaus.jackson.map.deser.StdDeserializer._parseInteger(StdDeserializer.java:264)
        at org.codehaus.jackson.map.deser.StdDeserializer$IntegerDeserializer.deserialize(StdDeserializer.java:826)
        at org.codehaus.jackson.map.deser.StdDeserializer$IntegerDeserializer.deserialize(StdDeserializer.java:813)
        at com.codahale.jerkson.deser.ImmutableMapDeserializer.deserialize(ImmutableMapDeserializer.scala:26)
        at com.codahale.jerkson.deser.ImmutableMapDeserializer.deserialize(ImmutableMapDeserializer.scala:11)
        at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2110)
        at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1002)
        at com.codahale.jerkson.Parser$class.parse(Parser.scala:81)
        ... 17 more

Maybe a jackson problem...

Exception with case classes nested within case classes

For a Play framework project I'm trying to parse nested case classes like so:

case class Inner(foo: String, bar: Int)
case class Outer(hello: String, world: Inner)
val o = Outer("adam", Inner("eve", 4))
val oJson = com.codahale.jerkson.Json.generate(o)
val o2 = com.codahale.jerkson.Json.parse\[Outer\]\(oJson\)

This breaks on the last line with an exception:

Caused by: org.codehaus.jackson.map.JsonMappingException: Unable to find a case accessor for controllers.Outer
at com.codahale.jerkson.deser.CaseClassDeserializer$$anonfun$4.apply(CaseClassDeserializer.scala:39) ~[jerkson_2.9.1.jar:na]
at com.codahale.jerkson.deser.CaseClassDeserializer$$anonfun$4.apply(CaseClassDeserializer.scala:39) ~[jerkson_2.9.1.jar:na]

(at least when I run it within Play, see: https://groups.google.com/d/msg/play-framework/MKNPYOj9LBA/Ll6Fch98ZBkJ )

The issue seems to stem from: https://github.com/codahale/jerkson/blob/master/src/main/scala/com/codahale/jerkson/deser/CaseClassDeserializer.scala#L36 where it looks like it doesn't find the relevant constructor?

???

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.