summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMathias <mathias@spray.cc>2011-12-07 10:39:48 +0100
committerMathias <mathias@spray.cc>2011-12-07 10:39:48 +0100
commit6d12a46772034109e08492caca3da4c77627bcfe (patch)
tree4c0ff36faec921f791123f2b17c738e161519be4 /src
parent6a5ccb2e6c37f7922db34f29c1f9cfd61a2397e8 (diff)
downloadspray-json-6d12a46772034109e08492caca3da4c77627bcfe.tar.gz
spray-json-6d12a46772034109e08492caca3da4c77627bcfe.tar.bz2
spray-json-6d12a46772034109e08492caca3da4c77627bcfe.zip
Add JsValue.asJsObject methods, simplifies JsObject matching
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/cc/spray/json/JsValue.scala20
-rw-r--r--src/test/scala/cc/spray/json/CustomFormatSpec.scala45
2 files changed, 61 insertions, 4 deletions
diff --git a/src/main/scala/cc/spray/json/JsValue.scala b/src/main/scala/cc/spray/json/JsValue.scala
index f4dbf91..d14312b 100644
--- a/src/main/scala/cc/spray/json/JsValue.scala
+++ b/src/main/scala/cc/spray/json/JsValue.scala
@@ -18,20 +18,29 @@
package cc.spray.json
-import collection.mutable.{LinkedHashMap, ListBuffer}
import collection.immutable.ListMap
/**
* The general type of a JSON AST node.
*/
-sealed trait JsValue {
+sealed abstract class JsValue {
override def toString = compactPrint
def toString(printer: (JsValue => String)) = printer(this)
def compactPrint = CompactPrinter(this)
def prettyPrint = PrettyPrinter(this)
def convertTo[T :JsonReader]: T = jsonReader[T].read(this)
+ /**
+ * Returns `this` if this JsValue is a JsObject, otherwise throws a DeserializationException with the given error msg.
+ */
+ def asJsObject(errorMsg: String = "JSON object expected"): JsObject = deserializationError(errorMsg)
+
+ /**
+ * Returns `this` if this JsValue is a JsObject, otherwise throws a DeserializationException.
+ */
+ def asJsObject: JsObject = asJsObject()
+
@deprecated("Superceded by 'convertTo'", "1.1.0")
def fromJson[T :JsonReader]: T = convertTo
}
@@ -39,7 +48,10 @@ sealed trait JsValue {
/**
* A JSON object.
*/
-case class JsObject(fields: Map[String, JsValue]) extends JsValue
+case class JsObject(fields: Map[String, JsValue]) extends JsValue {
+ override def asJsObject(errorMsg: String) = this
+ def getFields(fieldNames: String*): Seq[JsValue] = fieldNames.flatMap(fields.get)
+}
object JsObject {
// we use a ListMap in order to preserve the field order
def apply(members: JsField*) = new JsObject(ListMap(members: _*))
@@ -82,7 +94,7 @@ object JsNumber {
/**
* JSON Booleans.
*/
-sealed trait JsBoolean extends JsValue {
+sealed abstract class JsBoolean extends JsValue {
def value: Boolean
}
object JsBoolean {
diff --git a/src/test/scala/cc/spray/json/CustomFormatSpec.scala b/src/test/scala/cc/spray/json/CustomFormatSpec.scala
new file mode 100644
index 0000000..237e3f4
--- /dev/null
+++ b/src/test/scala/cc/spray/json/CustomFormatSpec.scala
@@ -0,0 +1,45 @@
+/*
+ * 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 cc.spray.json
+
+import org.specs2.mutable.Specification
+
+class CustomFormatSpec extends Specification with DefaultJsonProtocol {
+
+ case class MyType(name: String, value: Int)
+
+ implicit val MyTypeProtocol = new RootJsonFormat[MyType] {
+ def read(json: JsValue) = {
+ json.asJsObject.getFields("name", "value") match {
+ case Seq(JsString(name), JsNumber(value)) => MyType(name, value.toInt)
+ case _ => deserializationError("Expected fields: 'name' (JSON string) and 'value' (JSON number)")
+ }
+ }
+ def write(obj: MyType) = JsObject("name" -> JsString(obj.name), "value" -> JsNumber(obj.value))
+ }
+
+ "A custom JsonFormat built with 'asJsonObject'" should {
+ val value = MyType("bob", 42)
+ "correctly deserialize valid JSON content" in {
+ JsonParser("""{ "name": "bob", "value": 42 }""").convertTo[MyType] mustEqual value
+ }
+ "support full round-trip (de)serialization" in {
+ value.toJson.convertTo[MyType] mustEqual value
+ }
+ }
+
+} \ No newline at end of file