summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.markdown7
-rw-r--r--build.sbt24
-rw-r--r--src/main/scala/spray/json/ProductFormats.scala4
-rw-r--r--src/test/scala/spray/json/ProductFormatsSpec.scala27
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:
diff --git a/build.sbt b/build.sbt
index 0bad2b2..2517910 100644
--- a/build.sbt
+++ b/build.sbt
@@ -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
+ }
+ }
+
}