summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Odersky <jakob@odersky.com>2018-03-07 14:07:25 -0800
committerJakob Odersky <jakob@odersky.com>2019-06-10 23:22:15 +0200
commita43a10a12fd5653e6050c652024764416b71ab54 (patch)
tree19824c4e4eb31f849d51520d57a484e4f4ca0640
parentda8ed26cfed5e958eeb29a3444ff882a46090459 (diff)
downloadspray-json-a43a10a12fd5653e6050c652024764416b71ab54.tar.gz
spray-json-a43a10a12fd5653e6050c652024764416b71ab54.tar.bz2
spray-json-a43a10a12fd5653e6050c652024764416b71ab54.zip
Add support for ScalaJS and Scala Native
Binary compatibility with previous versions is maintained.
-rw-r--r--.travis.yml31
-rw-r--r--CHANGELOG13
-rw-r--r--README.markdown25
-rw-r--r--build.sbt168
-rw-r--r--js/src/main/boilerplate/spray/json/ProductFormatsInstances.scala.template39
-rw-r--r--js/src/main/scala/spray/json/ProductFormats.scala80
-rw-r--r--jvm/src/main/boilerplate/spray/json/ProductFormatsInstances.scala.template (renamed from src/main/boilerplate/spray/json/ProductFormatsInstances.scala.template)0
-rw-r--r--jvm/src/main/scala/spray/json/ProductFormats.scala (renamed from src/main/scala/spray/json/ProductFormats.scala)0
-rw-r--r--jvm/src/test/scala/spray/json/JsonParserSpecJvm.scala62
-rw-r--r--jvm/src/test/scala/spray/json/ProductFormatsSpec.scala (renamed from src/test/scala/spray/json/ProductFormatsSpec.scala)0
-rw-r--r--jvm/src/test/scala/spray/json/ReadmeSpec.scala (renamed from src/test/scala/spray/json/ReadmeSpec.scala)0
l---------native/src1
-rw-r--r--project/plugins.sbt6
-rw-r--r--publish.sbt27
-rw-r--r--shared/src/main/scala/spray/json/AdditionalFormats.scala (renamed from src/main/scala/spray/json/AdditionalFormats.scala)0
-rw-r--r--shared/src/main/scala/spray/json/BasicFormats.scala (renamed from src/main/scala/spray/json/BasicFormats.scala)0
-rw-r--r--shared/src/main/scala/spray/json/CollectionFormats.scala (renamed from src/main/scala/spray/json/CollectionFormats.scala)0
-rw-r--r--shared/src/main/scala/spray/json/CompactPrinter.scala (renamed from src/main/scala/spray/json/CompactPrinter.scala)0
-rw-r--r--shared/src/main/scala/spray/json/DefaultJsonProtocol.scala (renamed from src/main/scala/spray/json/DefaultJsonProtocol.scala)0
-rw-r--r--shared/src/main/scala/spray/json/JsValue.scala (renamed from src/main/scala/spray/json/JsValue.scala)0
-rw-r--r--shared/src/main/scala/spray/json/JsonFormat.scala (renamed from src/main/scala/spray/json/JsonFormat.scala)0
-rw-r--r--shared/src/main/scala/spray/json/JsonParser.scala (renamed from src/main/scala/spray/json/JsonParser.scala)0
-rw-r--r--shared/src/main/scala/spray/json/JsonParserSettings.scala (renamed from src/main/scala/spray/json/JsonParserSettings.scala)0
-rw-r--r--shared/src/main/scala/spray/json/JsonPrinter.scala (renamed from src/main/scala/spray/json/JsonPrinter.scala)0
-rw-r--r--shared/src/main/scala/spray/json/PrettyPrinter.scala (renamed from src/main/scala/spray/json/PrettyPrinter.scala)0
-rw-r--r--shared/src/main/scala/spray/json/SortedPrinter.scala (renamed from src/main/scala/spray/json/SortedPrinter.scala)0
-rw-r--r--shared/src/main/scala/spray/json/StandardFormats.scala (renamed from src/main/scala/spray/json/StandardFormats.scala)0
-rw-r--r--shared/src/main/scala/spray/json/package.scala (renamed from src/main/scala/spray/json/package.scala)0
-rw-r--r--shared/src/test/resources/test.json (renamed from src/test/resources/test.json)0
-rw-r--r--shared/src/test/scala/spray/json/AdditionalFormatsSpec.scala (renamed from src/test/scala/spray/json/AdditionalFormatsSpec.scala)0
-rw-r--r--shared/src/test/scala/spray/json/BasicFormatsSpec.scala (renamed from src/test/scala/spray/json/BasicFormatsSpec.scala)0
-rw-r--r--shared/src/test/scala/spray/json/CollectionFormatsSpec.scala (renamed from src/test/scala/spray/json/CollectionFormatsSpec.scala)0
-rw-r--r--shared/src/test/scala/spray/json/CompactPrinterSpec.scala (renamed from src/test/scala/spray/json/CompactPrinterSpec.scala)3
-rw-r--r--shared/src/test/scala/spray/json/CustomFormatSpec.scala (renamed from src/test/scala/spray/json/CustomFormatSpec.scala)0
-rw-r--r--shared/src/test/scala/spray/json/HashCodeCollider.scala (renamed from src/test/scala/spray/json/HashCodeCollider.scala)0
-rw-r--r--shared/src/test/scala/spray/json/JsonParserSpec.scala (renamed from src/test/scala/spray/json/JsonParserSpec.scala)40
-rw-r--r--shared/src/test/scala/spray/json/PrettyPrinterSpec.scala (renamed from src/test/scala/spray/json/PrettyPrinterSpec.scala)0
-rw-r--r--shared/src/test/scala/spray/json/RoundTripSpecs.scala (renamed from src/test/scala/spray/json/RoundTripSpecs.scala)0
-rw-r--r--shared/src/test/scala/spray/json/SortedPrinterSpec.scala (renamed from src/test/scala/spray/json/SortedPrinterSpec.scala)0
-rw-r--r--shared/src/test/scala/spray/json/StandardFormatsSpec.scala (renamed from src/test/scala/spray/json/StandardFormatsSpec.scala)0
40 files changed, 336 insertions, 159 deletions
diff --git a/.travis.yml b/.travis.yml
index d501ae9..eb8d2d8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,32 +1,27 @@
+# sudo required for installing dependencies of Scala Native
+sudo: required
language: scala
-scala:
- - 2.10.7
- - 2.11.12
- - 2.12.8
- - 2.13.0-RC3
-
jdk:
- oraclejdk8
-matrix:
- include:
- - jdk: openjdk11
- scala: 2.12.8
+before_install:
+ - curl https://raw.githubusercontent.com/scala-native/scala-native/4c2ce46242f872f3e7879810565147c4233cd52e/scripts/travis_setup.sh | bash -x
script:
- - sbt "++ ${TRAVIS_SCALA_VERSION}!" test mimaReportBinaryIssues
+ - sbt +test +mimaReportBinaryIssues
before_cache:
- - find $HOME/.ivy2 -name "ivydata-*.properties" -print -delete
- - find $HOME/.sbt -name "*.lock" -print -delete
+ - find $HOME/.sbt -name "*.lock" | xargs rm
+ - find $HOME/.ivy2 -name "ivydata-*.properties" | xargs rm
+ - rm -rf $HOME/.ivy2/{cache,local}/io.spray/
cache:
directories:
- $HOME/.ivy2/cache
- - $HOME/.sbt/boot
+ - $HOME/.sbt/boot/
-notifications:
- email:
- - johannes@spray.io
- - mathias@spray.io
+#notifications:
+# email:
+# - johannes@spray.io
+# - mathias@spray.io
diff --git a/CHANGELOG b/CHANGELOG
index 763d6b4..87237e7 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,16 @@
+Version 1.3.6 (UNRELEASED)
+--------------------------
+This version mainly updates the build and introduces support for
+cross-compiling spray to ScalaJS and Scala Native, in addition to
+traditional Scala on the JVM.
+
+Source and binary compatibility with the previous release is maintained
+for the JVM project. However, ScalaJS and Scala Native versions do not
+implement reflective product formats, meaning that there are no more
+`jsonFormatX()` methods on these platforms. The overloaded method
+`jsonFormat(<constructor>, <field_names>*)` is still available and may
+be used as a workaround.
+
Version 1.3.5 (2017-10-24)
--------------------------
diff --git a/README.markdown b/README.markdown
index 7c040db..7494184 100644
--- a/README.markdown
+++ b/README.markdown
@@ -17,6 +17,14 @@ as depicted in this diagram:
![Spray-JSON conversions](images/Conversions.png "Conversions possible with Spray-JSON")
+_spray-json_ is available for Scala on the JVM, ScalaJS and Scala Native<sup>1</sup>.
+
+<sup>1</sup>: *The versions for ScalaJS and Scala Native do not support generating
+case class formats through introspection, meaning that there are no `jsonFormatX`
+methods available on these platforms. See section
+[Providing JsonFormats for Case Classes](#providing-jsonformats-for-case-classes) below
+for an explanation and workaround.*
+
### Installation
_spray-json_ is available from maven central.
@@ -42,26 +50,26 @@ import DefaultJsonProtocol._ // if you don't supply your own Protocol (see below
and do one or more of the following:
1. Parse a JSON string into its Abstract Syntax Tree (AST) representation
-
+
```scala
val source = """{ "some": "JSON source" }"""
val jsonAst = source.parseJson // or JsonParser(source)
```
-
+
2. Print a JSON AST back to a String using either the `CompactPrinter` or the `PrettyPrinter`
-
+
```scala
val json = jsonAst.prettyPrint // or .compactPrint
```
-
+
3. Convert any Scala object to a JSON AST using the `toJson` extension method
-
+
```scala
val jsonAst = List(1, 2, 3).toJson
```
-
+
4. Convert a JSON AST to a Scala object with the `convertTo` method
-
+
```scala
val myObject = jsonAst.convertTo[MyObjectType]
```
@@ -130,6 +138,9 @@ method). The `jsonFormatX` methods try to extract the field names of your case c
field names or if your JSON objects use member names that differ from the case class fields you can also use
`jsonFormat` directly.
+*Note that spray-json for ScalaJS or Scala Native does not support the `jsonFormatX` methods, and hence using
+the `jsonFormat` overloads is required on these platforms.*
+
There is one additional quirk: If you explicitly declare the companion object for your case class the notation above will
stop working. You'll have to explicitly refer to the companion objects `apply` method to fix this:
diff --git a/build.sbt b/build.sbt
index c6ecc15..6dba46e 100644
--- a/build.sbt
+++ b/build.sbt
@@ -1,94 +1,80 @@
+// shadow sbt-scalajs' crossProject and CrossType until Scala.js 1.0.0 is released
+import sbtcrossproject.CrossPlugin.autoImport.{crossProject, CrossType}
import com.typesafe.tools.mima.core.{ProblemFilters, ReversedMissingMethodProblem}
-name := "spray-json"
-
-version := "1.3.6-SNAPSHOT"
-
-organization := "io.spray"
-
-organizationHomepage := Some(new URL("http://spray.io"))
-
-description := "A Scala library for easy and idiomatic JSON (de)serialization"
-
-homepage := Some(new URL("https://github.com/spray/spray-json"))
-
-startYear := Some(2011)
-
-licenses := Seq("Apache 2" -> new URL("http://www.apache.org/licenses/LICENSE-2.0.txt"))
-
-scalacOptions ++= Seq("-feature", "-language:_", "-unchecked", "-deprecation", "-Xlint", "-encoding", "utf8")
-
-resolvers += Opts.resolver.sonatypeReleases
-
-libraryDependencies ++= (CrossVersion.partialVersion(scalaVersion.value) match {
- case Some((2, 10)) => Seq(
- "org.specs2" %% "specs2-core" % "3.10.0" % "test",
- "org.specs2" %% "specs2-scalacheck" % "3.10.0" % "test",
- "org.scalacheck" %% "scalacheck" % "1.14.0" % "test"
- )
- case Some((2, n)) if n >= 11 => Seq(
- "org.specs2" %% "specs2-core" % "4.5.1" % "test",
- "org.specs2" %% "specs2-scalacheck" % "4.5.1" % "test",
- "org.scalacheck" %% "scalacheck" % "1.14.0" % "test"
+lazy val scala210 = "2.10.7"
+lazy val scala211 = "2.11.12"
+lazy val scala212 = "2.12.8"
+lazy val scala213 = "2.13.0"
+
+lazy val sprayJson =
+ crossProject(JVMPlatform, JSPlatform, NativePlatform)
+ .crossType(CrossType.Full)
+ .in(file("."))
+ .settings(
+ name := "spray-json",
+ version := "1.3.6-SNAPSHOT",
+ scalaVersion := crossScalaVersions.value.head,
+ scalacOptions ++= Seq("-feature", "-language:_", "-unchecked", "-deprecation", "-Xlint", "-encoding", "utf8"),
+ (scalacOptions in doc) ++= Seq("-doc-title", name.value + " " + version.value),
+ scalaBinaryVersion := {
+ val sV = scalaVersion.value
+ if (CrossVersion.isScalaApiCompatible(sV))
+ CrossVersion.binaryScalaVersion(sV)
+ else
+ sV
+ },
+ // Workaround for "Shared resource directory is ignored"
+ // https://github.com/portable-scala/sbt-crossproject/issues/74
+ unmanagedResourceDirectories in Test += (baseDirectory in ThisBuild).value / "shared/src/test/resources"
+ )
+ .enablePlugins(spray.boilerplate.BoilerplatePlugin)
+ .platformsSettings(JVMPlatform, JSPlatform)(
+ libraryDependencies ++= (CrossVersion.partialVersion(scalaVersion.value) match {
+ case Some((2, 10)) => Seq(
+ "org.specs2" %%% "specs2-core" % "3.8.9" % "test",
+ "org.specs2" %%% "specs2-scalacheck" % "3.8.9" % "test",
+ "org.scalacheck" %%% "scalacheck" % "1.13.4" % "test"
+ )
+ case Some((2, n)) if n >= 11 => Seq(
+ "org.specs2" %%% "specs2-core" % "4.5.1" % "test",
+ "org.specs2" %%% "specs2-scalacheck" % "4.5.1" % "test",
+ "org.scalacheck" %%% "scalacheck" % "1.14.0" % "test"
+ )
+ case _ => Nil
+ })
+ )
+ .configurePlatforms(JVMPlatform)(_.enablePlugins(SbtOsgi))
+ .jvmSettings(
+ crossScalaVersions := Seq(scala213, scala212, scala211, scala210),
+ OsgiKeys.exportPackage := Seq("""spray.json.*;version="${Bundle-Version}""""),
+ OsgiKeys.importPackage := Seq("""scala.*;version="$<range;[==,=+);%s>"""".format(scalaVersion.value)),
+ OsgiKeys.importPackage ++= Seq("""spray.json;version="${Bundle-Version}"""", "*"),
+ OsgiKeys.additionalHeaders := Map("-removeheaders" -> "Include-Resource,Private-Package"),
+ mimaPreviousArtifacts := (CrossVersion.partialVersion(scalaVersion.value) match {
+ case Some((2, 13)) => Set.empty
+ case _ => Set("io.spray" %% "spray-json" % "1.3.5")
+ }),
+ mimaBinaryIssueFilters := Seq(
+ ProblemFilters.exclude[ReversedMissingMethodProblem]("spray.json.PrettyPrinter.organiseMembers")
+ )
+ )
+ .jsSettings(
+ crossScalaVersions := Seq(scala212, scala211)
+ )
+ .nativeSettings(
+ crossScalaVersions := Seq(scala211),
+ // Disable tests in Scala Native until testing frameworks for it become available
+ unmanagedSourceDirectories in Test := Seq.empty
+ )
+
+lazy val sprayJsonJVM = sprayJson.jvm
+lazy val sprayJsonJS = sprayJson.js
+lazy val sprayJsonNative = sprayJson.native
+
+lazy val root = (project in file("."))
+ .aggregate(sprayJsonJVM, sprayJsonJS, sprayJsonNative)
+ .settings(
+ publish := {},
+ publishLocal := {}
)
- case _ => Nil
-})
-
-(scalacOptions in doc) ++= Seq("-doc-title", name.value + " " + version.value)
-
-// generate boilerplate
-enablePlugins(BoilerplatePlugin)
-
-// OSGi settings
-enablePlugins(SbtOsgi)
-
-OsgiKeys.exportPackage := Seq("""spray.json.*;version="${Bundle-Version}"""")
-
-OsgiKeys.importPackage := Seq("""scala.*;version="$<range;[==,=+);%s>"""".format(scalaVersion.value))
-
-OsgiKeys.importPackage ++= Seq("""spray.json;version="${Bundle-Version}"""", "*")
-
-OsgiKeys.additionalHeaders := Map("-removeheaders" -> "Include-Resource,Private-Package")
-
-// Migration Manager
-mimaPreviousArtifacts := (CrossVersion.partialVersion(scalaVersion.value) match {
- case Some((2, 13)) => Set.empty
- case _ =>
- Set("1.3.2", "1.3.3", "1.3.4").map { v =>
- "io.spray" %% "spray-json" % v
- }
-})
-
-mimaBinaryIssueFilters := Seq(
- ProblemFilters.exclude[ReversedMissingMethodProblem]("spray.json.PrettyPrinter.organiseMembers")
-)
-
-///////////////
-// publishing
-///////////////
-
-crossScalaVersions := Seq("2.12.8", "2.10.7", "2.11.12", "2.13.0-RC3")
-
-publishMavenStyle := true
-
-useGpg := true
-
-publishTo := {
- val nexus = "https://oss.sonatype.org/"
- if (version.value.trim.endsWith("SNAPSHOT"))
- Some("snapshots" at nexus + "content/repositories/snapshots")
- else
- Some("releases" at nexus + "service/local/staging/deploy/maven2")
-}
-
-pomIncludeRepository := { _ => false }
-
-pomExtra :=
- <scm>
- <url>git://github.com/spray/spray.git</url>
- <connection>scm:git:git@github.com:spray/spray.git</connection>
- </scm>
- <developers>
- <developer><id>sirthias</id><name>Mathias Doenitz</name></developer>
- <developer><id>jrudolph</id><name>Johannes Rudolph</name></developer>
- </developers>
diff --git a/js/src/main/boilerplate/spray/json/ProductFormatsInstances.scala.template b/js/src/main/boilerplate/spray/json/ProductFormatsInstances.scala.template
new file mode 100644
index 0000000..d6f83f7
--- /dev/null
+++ b/js/src/main/boilerplate/spray/json/ProductFormatsInstances.scala.template
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2011,2012 Mathias Doenitz, Johannes Rudolph
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package spray.json
+
+trait ProductFormatsInstances { self: ProductFormats with StandardFormats =>
+[# // Case classes with 1 parameters
+
+ def jsonFormat[[#P1 :JF#], T <: Product](construct: ([#P1#]) => T, [#fieldName1: String#]): RootJsonFormat[T] = new RootJsonFormat[T]{
+ def write(p: T) = {
+ val fields = new collection.mutable.ListBuffer[(String, JsValue)]
+ fields.sizeHint(1 * 2)
+ [#fields ++= productElement##2Field[P1](fieldName1, p, 0)#
+ ]
+ JsObject(fields: _*)
+ }
+ def read(value: JsValue) = {
+ [#val p1V = fromField[P1](value, fieldName1)#
+ ]
+ construct([#p1V#])
+ }
+ }#
+
+
+]
+}
diff --git a/js/src/main/scala/spray/json/ProductFormats.scala b/js/src/main/scala/spray/json/ProductFormats.scala
new file mode 100644
index 0000000..bc06eac
--- /dev/null
+++ b/js/src/main/scala/spray/json/ProductFormats.scala
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011 Mathias Doenitz
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package spray.json
+
+/**
+ * Provides the helpers for constructing custom JsonFormat implementations for types implementing the Product trait
+ * (especially case classes)
+ */
+trait ProductFormats extends ProductFormatsInstances {
+ this: StandardFormats =>
+
+ def jsonFormat0[T](construct: () => T): RootJsonFormat[T] =
+ new RootJsonFormat[T] {
+ def write(p: T) = JsObject()
+ def read(value: JsValue) = value match {
+ case JsObject(_) => construct()
+ case _ => throw new DeserializationException("Object expected")
+ }
+ }
+
+ // helpers
+
+ protected def productElement2Field[T](fieldName: String, p: Product, ix: Int, rest: List[JsField] = Nil)
+ (implicit writer: JsonWriter[T]): List[JsField] = {
+ val value = p.productElement(ix).asInstanceOf[T]
+ writer match {
+ case _: OptionFormat[_] if (value == None) => rest
+ case _ => (fieldName, writer.write(value)) :: rest
+ }
+ }
+
+ protected def fromField[T](value: JsValue, fieldName: String)
+ (implicit reader: JsonReader[T]) = value match {
+ case x: JsObject if
+ (reader.isInstanceOf[OptionFormat[_]] &
+ !x.fields.contains(fieldName)) =>
+ None.asInstanceOf[T]
+ case x: JsObject =>
+ try reader.read(x.fields(fieldName))
+ catch {
+ case e: NoSuchElementException =>
+ deserializationError("Object is missing required member '" + fieldName + "'", e, fieldName :: Nil)
+ case DeserializationException(msg, cause, fieldNames) =>
+ deserializationError(msg, cause, fieldName :: fieldNames)
+ }
+ case _ => deserializationError("Object expected in field '" + fieldName + "'", fieldNames = fieldName :: Nil)
+ }
+
+}
+
+/**
+ * This trait supplies an alternative rendering mode for optional case class members.
+ * Normally optional members that are undefined (`None`) are not rendered at all.
+ * By mixing in this trait into your custom JsonProtocol you can enforce the rendering of undefined members as `null`.
+ * (Note that this only affect JSON writing, spray-json will always read missing optional members as well as `null`
+ * optional members as `None`.)
+ */
+trait NullOptions extends ProductFormats {
+ this: StandardFormats =>
+
+ override protected def productElement2Field[T](fieldName: String, p: Product, ix: Int, rest: List[JsField])
+ (implicit writer: JsonWriter[T]) = {
+ val value = p.productElement(ix).asInstanceOf[T]
+ (fieldName, writer.write(value)) :: rest
+ }
+}
diff --git a/src/main/boilerplate/spray/json/ProductFormatsInstances.scala.template b/jvm/src/main/boilerplate/spray/json/ProductFormatsInstances.scala.template
index fa0d875..fa0d875 100644
--- a/src/main/boilerplate/spray/json/ProductFormatsInstances.scala.template
+++ b/jvm/src/main/boilerplate/spray/json/ProductFormatsInstances.scala.template
diff --git a/src/main/scala/spray/json/ProductFormats.scala b/jvm/src/main/scala/spray/json/ProductFormats.scala
index 81a48af..81a48af 100644
--- a/src/main/scala/spray/json/ProductFormats.scala
+++ b/jvm/src/main/scala/spray/json/ProductFormats.scala
diff --git a/jvm/src/test/scala/spray/json/JsonParserSpecJvm.scala b/jvm/src/test/scala/spray/json/JsonParserSpecJvm.scala
new file mode 100644
index 0000000..c0345e1
--- /dev/null
+++ b/jvm/src/test/scala/spray/json/JsonParserSpecJvm.scala
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2011 Mathias Doenitz
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package spray.json
+
+import org.specs2.mutable._
+import scala.util.control.NonFatal
+
+class JsonParserSpecJvm extends Specification {
+
+ "The JsonParser (on the JVM)" should {
+ "be reentrant" in {
+ import scala.concurrent.{Await, Future}
+ import scala.concurrent.duration._
+ import scala.concurrent.ExecutionContext.Implicits.global
+
+ val largeJsonSource = scala.io.Source.fromInputStream(getClass.getResourceAsStream("/test.json")).mkString
+ val list = Await.result(
+ Future.traverse(List.fill(20)(largeJsonSource))(src => Future(JsonParser(src))),
+ 5.seconds
+ )
+ list.map(_.asInstanceOf[JsObject].fields("questions").asInstanceOf[JsArray].elements.size) === List.fill(20)(100)
+ }
+ "fail gracefully for deeply nested structures" in {
+ val queue = new java.util.ArrayDeque[String]()
+
+ // testing revealed that each recursion will need approx. 280 bytes of stack space
+ val depth = 1500
+ val runnable = new Runnable {
+ override def run(): Unit =
+ try {
+ val nested = "[{\"key\":" * (depth / 2)
+ JsonParser(nested)
+ queue.push("didn't fail")
+ } catch {
+ case s: StackOverflowError => queue.push("stackoverflow")
+ case NonFatal(e) =>
+ queue.push(s"nonfatal: ${e.getMessage}")
+ }
+ }
+
+ val thread = new Thread(null, runnable, "parser-test", 655360)
+ thread.start()
+ thread.join()
+ queue.peek() === "nonfatal: JSON input nested too deeply:JSON input was nested more deeply than the configured limit of maxNesting = 1000"
+ }
+ }
+
+}
diff --git a/src/test/scala/spray/json/ProductFormatsSpec.scala b/jvm/src/test/scala/spray/json/ProductFormatsSpec.scala
index f42c46d..f42c46d 100644
--- a/src/test/scala/spray/json/ProductFormatsSpec.scala
+++ b/jvm/src/test/scala/spray/json/ProductFormatsSpec.scala
diff --git a/src/test/scala/spray/json/ReadmeSpec.scala b/jvm/src/test/scala/spray/json/ReadmeSpec.scala
index 306b656..306b656 100644
--- a/src/test/scala/spray/json/ReadmeSpec.scala
+++ b/jvm/src/test/scala/spray/json/ReadmeSpec.scala
diff --git a/native/src b/native/src
new file mode 120000
index 0000000..f2bb155
--- /dev/null
+++ b/native/src
@@ -0,0 +1 @@
+../js/src/ \ No newline at end of file
diff --git a/project/plugins.sbt b/project/plugins.sbt
index 41badc2..3cdb1d8 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -3,5 +3,9 @@ addSbtPlugin("io.spray" % "sbt-boilerplate" % "0.6.1")
addSbtPlugin("com.typesafe.sbt" % "sbt-osgi" % "0.9.5")
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.2")
-
addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.3.0")
+
+addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "0.6.0")
+addSbtPlugin("org.portable-scala" % "sbt-scala-native-crossproject" % "0.6.0")
+addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.27")
+addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.3.8")
diff --git a/publish.sbt b/publish.sbt
new file mode 100644
index 0000000..4dfcd29
--- /dev/null
+++ b/publish.sbt
@@ -0,0 +1,27 @@
+inThisBuild(Seq(
+ organization := "io.spray",
+ organizationHomepage := Some(new URL("http://spray.io")),
+ description := "A Scala library for easy and idiomatic JSON (de)serialization",
+ homepage := Some(new URL("https://github.com/spray/spray-json")),
+ startYear := Some(2011),
+ licenses := Seq("Apache 2" -> new URL("http://www.apache.org/licenses/LICENSE-2.0.txt")),
+ publishMavenStyle := true,
+ useGpg := true,
+ publishTo := {
+ val nexus = "https://oss.sonatype.org/"
+ if (version.value.trim.endsWith("SNAPSHOT"))
+ Some("snapshots" at nexus + "content/repositories/snapshots")
+ else
+ Some("releases" at nexus + "service/local/staging/deploy/maven2")
+ },
+ pomIncludeRepository := { _ => false },
+ pomExtra :=
+ <scm>
+ <url>git://github.com/spray/spray.git</url>
+ <connection>scm:git:git@github.com:spray/spray.git</connection>
+ </scm>
+ <developers>
+ <developer><id>sirthias</id><name>Mathias Doenitz</name></developer>
+ <developer><id>jrudolph</id><name>Johannes Rudolph</name></developer>
+ </developers>
+))
diff --git a/src/main/scala/spray/json/AdditionalFormats.scala b/shared/src/main/scala/spray/json/AdditionalFormats.scala
index fbabb0b..fbabb0b 100644
--- a/src/main/scala/spray/json/AdditionalFormats.scala
+++ b/shared/src/main/scala/spray/json/AdditionalFormats.scala
diff --git a/src/main/scala/spray/json/BasicFormats.scala b/shared/src/main/scala/spray/json/BasicFormats.scala
index 2e6342f..2e6342f 100644
--- a/src/main/scala/spray/json/BasicFormats.scala
+++ b/shared/src/main/scala/spray/json/BasicFormats.scala
diff --git a/src/main/scala/spray/json/CollectionFormats.scala b/shared/src/main/scala/spray/json/CollectionFormats.scala
index ef94297..ef94297 100644
--- a/src/main/scala/spray/json/CollectionFormats.scala
+++ b/shared/src/main/scala/spray/json/CollectionFormats.scala
diff --git a/src/main/scala/spray/json/CompactPrinter.scala b/shared/src/main/scala/spray/json/CompactPrinter.scala
index 7260c2f..7260c2f 100644
--- a/src/main/scala/spray/json/CompactPrinter.scala
+++ b/shared/src/main/scala/spray/json/CompactPrinter.scala
diff --git a/src/main/scala/spray/json/DefaultJsonProtocol.scala b/shared/src/main/scala/spray/json/DefaultJsonProtocol.scala
index 4c93184..4c93184 100644
--- a/src/main/scala/spray/json/DefaultJsonProtocol.scala
+++ b/shared/src/main/scala/spray/json/DefaultJsonProtocol.scala
diff --git a/src/main/scala/spray/json/JsValue.scala b/shared/src/main/scala/spray/json/JsValue.scala
index 9ed94da..9ed94da 100644
--- a/src/main/scala/spray/json/JsValue.scala
+++ b/shared/src/main/scala/spray/json/JsValue.scala
diff --git a/src/main/scala/spray/json/JsonFormat.scala b/shared/src/main/scala/spray/json/JsonFormat.scala
index c4915cc..c4915cc 100644
--- a/src/main/scala/spray/json/JsonFormat.scala
+++ b/shared/src/main/scala/spray/json/JsonFormat.scala
diff --git a/src/main/scala/spray/json/JsonParser.scala b/shared/src/main/scala/spray/json/JsonParser.scala
index 7dfae0a..7dfae0a 100644
--- a/src/main/scala/spray/json/JsonParser.scala
+++ b/shared/src/main/scala/spray/json/JsonParser.scala
diff --git a/src/main/scala/spray/json/JsonParserSettings.scala b/shared/src/main/scala/spray/json/JsonParserSettings.scala
index 8c76b0a..8c76b0a 100644
--- a/src/main/scala/spray/json/JsonParserSettings.scala
+++ b/shared/src/main/scala/spray/json/JsonParserSettings.scala
diff --git a/src/main/scala/spray/json/JsonPrinter.scala b/shared/src/main/scala/spray/json/JsonPrinter.scala
index 42cbab4..42cbab4 100644
--- a/src/main/scala/spray/json/JsonPrinter.scala
+++ b/shared/src/main/scala/spray/json/JsonPrinter.scala
diff --git a/src/main/scala/spray/json/PrettyPrinter.scala b/shared/src/main/scala/spray/json/PrettyPrinter.scala
index 7526dab..7526dab 100644
--- a/src/main/scala/spray/json/PrettyPrinter.scala
+++ b/shared/src/main/scala/spray/json/PrettyPrinter.scala
diff --git a/src/main/scala/spray/json/SortedPrinter.scala b/shared/src/main/scala/spray/json/SortedPrinter.scala
index 28db225..28db225 100644
--- a/src/main/scala/spray/json/SortedPrinter.scala
+++ b/shared/src/main/scala/spray/json/SortedPrinter.scala
diff --git a/src/main/scala/spray/json/StandardFormats.scala b/shared/src/main/scala/spray/json/StandardFormats.scala
index e59de64..e59de64 100644
--- a/src/main/scala/spray/json/StandardFormats.scala
+++ b/shared/src/main/scala/spray/json/StandardFormats.scala
diff --git a/src/main/scala/spray/json/package.scala b/shared/src/main/scala/spray/json/package.scala
index a8a42f0..a8a42f0 100644
--- a/src/main/scala/spray/json/package.scala
+++ b/shared/src/main/scala/spray/json/package.scala
diff --git a/src/test/resources/test.json b/shared/src/test/resources/test.json
index 8308d37..8308d37 100644
--- a/src/test/resources/test.json
+++ b/shared/src/test/resources/test.json
diff --git a/src/test/scala/spray/json/AdditionalFormatsSpec.scala b/shared/src/test/scala/spray/json/AdditionalFormatsSpec.scala
index 01127e6..01127e6 100644
--- a/src/test/scala/spray/json/AdditionalFormatsSpec.scala
+++ b/shared/src/test/scala/spray/json/AdditionalFormatsSpec.scala
diff --git a/src/test/scala/spray/json/BasicFormatsSpec.scala b/shared/src/test/scala/spray/json/BasicFormatsSpec.scala
index 454e1cc..454e1cc 100644
--- a/src/test/scala/spray/json/BasicFormatsSpec.scala
+++ b/shared/src/test/scala/spray/json/BasicFormatsSpec.scala
diff --git a/src/test/scala/spray/json/CollectionFormatsSpec.scala b/shared/src/test/scala/spray/json/CollectionFormatsSpec.scala
index 9d6970b..9d6970b 100644
--- a/src/test/scala/spray/json/CollectionFormatsSpec.scala
+++ b/shared/src/test/scala/spray/json/CollectionFormatsSpec.scala
diff --git a/src/test/scala/spray/json/CompactPrinterSpec.scala b/shared/src/test/scala/spray/json/CompactPrinterSpec.scala
index 6a9560b..691daa9 100644
--- a/src/test/scala/spray/json/CompactPrinterSpec.scala
+++ b/shared/src/test/scala/spray/json/CompactPrinterSpec.scala
@@ -39,9 +39,6 @@ class CompactPrinterSpec extends Specification {
"print JsNumber(1.23) to '1.23'" in {
CompactPrinter(JsNumber(1.23)) mustEqual "1.23"
}
- "print JsNumber(-1E10) to '-1E10'" in {
- CompactPrinter(JsNumber(-1E10)) mustEqual "-1.0E+10"
- }
"print JsNumber(12.34e-10) to '12.34e-10'" in {
CompactPrinter(JsNumber(12.34e-10)) mustEqual "1.234E-9"
}
diff --git a/src/test/scala/spray/json/CustomFormatSpec.scala b/shared/src/test/scala/spray/json/CustomFormatSpec.scala
index 2397abc..2397abc 100644
--- a/src/test/scala/spray/json/CustomFormatSpec.scala
+++ b/shared/src/test/scala/spray/json/CustomFormatSpec.scala
diff --git a/src/test/scala/spray/json/HashCodeCollider.scala b/shared/src/test/scala/spray/json/HashCodeCollider.scala
index 57388b9..57388b9 100644
--- a/src/test/scala/spray/json/HashCodeCollider.scala
+++ b/shared/src/test/scala/spray/json/HashCodeCollider.scala
diff --git a/src/test/scala/spray/json/JsonParserSpec.scala b/shared/src/test/scala/spray/json/JsonParserSpec.scala
index 1ca0ddc..0793e66 100644
--- a/src/test/scala/spray/json/JsonParserSpec.scala
+++ b/shared/src/test/scala/spray/json/JsonParserSpec.scala
@@ -18,8 +18,6 @@ package spray.json
import org.specs2.mutable._
-import scala.util.control.NonFatal
-
class JsonParserSpec extends Specification {
"The JsonParser" should {
@@ -74,20 +72,8 @@ class JsonParserSpec extends Specification {
val json = JsString("£0.99")
JsonParser(json.prettyPrint.getBytes("UTF-8")) === json
}
- "be reentrant" in {
- import scala.concurrent.{Await, Future}
- import scala.concurrent.duration._
- import scala.concurrent.ExecutionContext.Implicits.global
-
- val largeJsonSource = scala.io.Source.fromInputStream(getClass.getResourceAsStream("/test.json")).mkString
- val list = Await.result(
- Future.traverse(List.fill(20)(largeJsonSource))(src => Future(JsonParser(src))),
- 5.seconds
- )
- list.map(_.asInstanceOf[JsObject].fields("questions").asInstanceOf[JsArray].elements.size) === List.fill(20)(100)
- }
"not show bad performance characteristics when object keys' hashCodes collide" in {
- val numKeys = 10000
+ val numKeys = 100000
val value = "null"
val regularKeys = Iterator.from(1).map(i => s"key_$i").take(numKeys)
@@ -153,30 +139,6 @@ class JsonParserSpec extends Specification {
}
}
- "fail gracefully for deeply nested structures" in {
- val queue = new java.util.ArrayDeque[String]()
-
- // testing revealed that each recursion will need approx. 280 bytes of stack space
- val depth = 1500
- val runnable = new Runnable {
- override def run(): Unit =
- try {
- val nested = "[{\"key\":" * (depth / 2)
- JsonParser(nested)
- queue.push("didn't fail")
- } catch {
- case s: StackOverflowError => queue.push("stackoverflow")
- case NonFatal(e) =>
- queue.push(s"nonfatal: ${e.getMessage}")
- }
- }
-
- val thread = new Thread(null, runnable, "parser-test", 655360)
- thread.start()
- thread.join()
- queue.peek() === "nonfatal: JSON input nested too deeply:JSON input was nested more deeply than the configured limit of maxNesting = 1000"
- }
-
"parse multiple values when allowTrailingInput" in {
val parser = new JsonParser("""{"key":1}{"key":2}""")
parser.parseJsValue(true) === JsObject("key" -> JsNumber(1))
diff --git a/src/test/scala/spray/json/PrettyPrinterSpec.scala b/shared/src/test/scala/spray/json/PrettyPrinterSpec.scala
index b547f59..b547f59 100644
--- a/src/test/scala/spray/json/PrettyPrinterSpec.scala
+++ b/shared/src/test/scala/spray/json/PrettyPrinterSpec.scala
diff --git a/src/test/scala/spray/json/RoundTripSpecs.scala b/shared/src/test/scala/spray/json/RoundTripSpecs.scala
index 6bee7b4..6bee7b4 100644
--- a/src/test/scala/spray/json/RoundTripSpecs.scala
+++ b/shared/src/test/scala/spray/json/RoundTripSpecs.scala
diff --git a/src/test/scala/spray/json/SortedPrinterSpec.scala b/shared/src/test/scala/spray/json/SortedPrinterSpec.scala
index f91640e..f91640e 100644
--- a/src/test/scala/spray/json/SortedPrinterSpec.scala
+++ b/shared/src/test/scala/spray/json/SortedPrinterSpec.scala
diff --git a/src/test/scala/spray/json/StandardFormatsSpec.scala b/shared/src/test/scala/spray/json/StandardFormatsSpec.scala
index 833f06a..833f06a 100644
--- a/src/test/scala/spray/json/StandardFormatsSpec.scala
+++ b/shared/src/test/scala/spray/json/StandardFormatsSpec.scala