diff options
-rw-r--r-- | README.markdown | 7 | ||||
-rw-r--r-- | build.sbt | 24 | ||||
-rw-r--r-- | src/main/scala/spray/json/ProductFormats.scala | 4 | ||||
-rw-r--r-- | src/test/scala/spray/json/ProductFormatsSpec.scala | 27 |
4 files changed, 48 insertions, 14 deletions
diff --git a/README.markdown b/README.markdown index 0f274b7..e54f097 100644 --- a/README.markdown +++ b/README.markdown @@ -11,13 +11,15 @@ It sports the following features: ### Installation _spray-json_ is available from the [repo.spray.io] repository. -The latest release is `1.2.3` and is built against Scala 2.9.2 as well as Scala 2.10.0-RC3. +The latest release is `1.2.3` and is built against Scala 2.9.2 as well as Scala 2.10.0. If you use SBT you can include _spray-json_ in your project with + resolvers += "spray" at "http://repo.spray.io/" + "io.spray" %% "spray-json" % "1.2.3" cross CrossVersion.full -(the trailing "cross CrossVersion.full" modifier is only required for SBT 0.12.x) +(the trailing "cross CrossVersion.full" modifier is only required when using SBT 0.12.x with Scala < 2.10) _spray-json_ has only one dependency: the parsing library [parboiled][] (which is also a dependency of _spray-http_, so if you use _spray-json_ together with other modules of the *spray* @@ -30,6 +32,7 @@ _spray-json_ is really easy to use. Just bring all relevant elements in scope with import spray.json._ + import DefaultJsonProtocol._ // !!! IMPORTANT, else `convertTo` and `toJson` won't work and do one or more of the following: @@ -14,21 +14,24 @@ startYear := Some(2011) licenses := Seq("Apache 2" -> new URL("http://www.apache.org/licenses/LICENSE-2.0.txt")) -scalaVersion := "2.10.0-RC3" +scalaVersion := "2.10.0" scalacOptions <<= scalaVersion map { - case x if x startsWith "2.9" => - Seq("-unchecked", "-deprecation", "-encoding", "utf8") - case x if x startsWith "2.10" => - Seq("-feature", "-language:implicitConversions", "-unchecked", "-deprecation", "-encoding", "utf8") + case "2.9.2" => Seq("-unchecked", "-deprecation", "-encoding", "utf8") + case "2.10.0" => Seq("-feature", "-language:implicitConversions", "-unchecked", "-deprecation", "-encoding", "utf8") } resolvers += Opts.resolver.sonatypeReleases -libraryDependencies ++= Seq( - "org.parboiled" %% "parboiled-scala" % "1.1.4" % "compile", - "org.specs2" %% "specs2" % "1.12.3" % "test" -) +libraryDependencies <++= scalaVersion { sv => + Seq( + "org.parboiled" %% "parboiled-scala" % "1.1.4" % "compile", + sv match { + case "2.9.2" => "org.specs2" %% "specs2" % "1.12.3" % "test" + case "2.10.0" => "org.specs2" %% "specs2" % "1.13" % "test" + } + ) +} scaladocOptions <<= (name, version).map { (n, v) => Seq("-doc-title", n + " " + v) } @@ -37,7 +40,7 @@ scaladocOptions <<= (name, version).map { (n, v) => Seq("-doc-title", n + " " + // publishing /////////////// -crossScalaVersions := Seq("2.9.2", "2.10.0-RC3") +crossScalaVersions := Seq("2.9.2", "2.10.0") scalaBinaryVersion <<= scalaVersion(sV => if (CrossVersion.isStable(sV)) CrossVersion.binaryScalaVersion(sV) else sV) @@ -59,7 +62,6 @@ publishTo <<= version { version => // ls-sbt /////////////// - seq(lsSettings:_*) (LsKeys.tags in LsKeys.lsync) := Seq("json") diff --git a/src/main/scala/spray/json/ProductFormats.scala b/src/main/scala/spray/json/ProductFormats.scala index b920d0a..1f5f7cf 100644 --- a/src/main/scala/spray/json/ProductFormats.scala +++ b/src/main/scala/spray/json/ProductFormats.scala @@ -16,6 +16,8 @@ package spray.json +import java.lang.reflect.Modifier + /** * Provides the helpers for constructing custom JsonFormat implementations for types implementing the Product trait * (especially case classes) @@ -507,7 +509,7 @@ trait ProductFormats { // that lexical sorting of ...8(), ...9(), ...10() is not correct, so we extract N and sort by N.toInt val copyDefaultMethods = clazz.getMethods.filter(_.getName.startsWith("copy$default$")).sortBy( _.getName.drop("copy$default$".length).takeWhile(_ != '(').toInt) - val fields = clazz.getDeclaredFields.filterNot(_.getName.startsWith("$")) + val fields = clazz.getDeclaredFields.filterNot(f => f.getName.startsWith("$") || Modifier.isTransient(f.getModifiers)) if (copyDefaultMethods.length != fields.length) sys.error("Case class " + clazz.getName + " declares additional fields") if (fields.zip(copyDefaultMethods).exists { case (f, m) => f.getType != m.getReturnType }) diff --git a/src/test/scala/spray/json/ProductFormatsSpec.scala b/src/test/scala/spray/json/ProductFormatsSpec.scala index e452639..5a07b4f 100644 --- a/src/test/scala/spray/json/ProductFormatsSpec.scala +++ b/src/test/scala/spray/json/ProductFormatsSpec.scala @@ -22,11 +22,15 @@ class ProductFormatsSpec extends Specification { case class Test2(a: Int, b: Option[Double]) case class Test3[A, B](as: List[A], bs: List[B]) + case class TestTransient(a: Int, b: Option[Double]) { + @transient var c = false + } trait TestProtocol { this: DefaultJsonProtocol => implicit val test2Format = jsonFormat2(Test2) implicit def test3Format[A: JsonFormat, B: JsonFormat] = jsonFormat2(Test3.apply[A, B]) + implicit def testTransientFormat = jsonFormat2(TestTransient) } object TestProtocol1 extends DefaultJsonProtocol with TestProtocol object TestProtocol2 extends DefaultJsonProtocol with TestProtocol with NullOptions @@ -84,4 +88,27 @@ class ProductFormatsSpec extends Specification { } } + "A JsonFormat for a generic case class with an explicitly provided type parameter" should { + "support the jsonFormat1 syntax" in { + case class Box[A](a: A) + object BoxProtocol extends DefaultJsonProtocol { + implicit val boxFormat = jsonFormat1(Box[Int]) + } + import BoxProtocol._ + Box(42).toJson === JsObject(Map("a" -> JsNumber(42))) + } + } + + "A JsonFormat for a case class with transient fields and created with `jsonFormat`" should { + import TestProtocol1._ + val obj = TestTransient(42, Some(4.2)) + val json = JsObject("a" -> JsNumber(42), "b" -> JsNumber(4.2)) + "convert to a respective JsObject" in { + obj.toJson mustEqual json + } + "convert a JsObject to the respective case class instance" in { + json.convertTo[TestTransient] mustEqual obj + } + } + } |