From 94b1fba92d40568c642a0b86c719c4bcc0865b54 Mon Sep 17 00:00:00 2001 From: Mathias Date: Tue, 6 Dec 2011 13:22:37 +0100 Subject: Remove JsField, turn JsObject(List[JsField]) into JsObject(Map[String, JsValue]) --- .../scala/cc/spray/json/CollectionFormats.scala | 9 +++---- src/main/scala/cc/spray/json/CompactPrinter.scala | 6 ++--- .../cc/spray/json/DeserializationException.scala | 2 +- src/main/scala/cc/spray/json/JsValue.scala | 21 ++++++---------- src/main/scala/cc/spray/json/JsonParser.scala | 4 ++-- src/main/scala/cc/spray/json/PrettyPrinter.scala | 6 ++--- src/main/scala/cc/spray/json/ProductFormats.scala | 28 +++++++++++----------- src/main/scala/cc/spray/json/package.scala | 2 ++ 8 files changed, 37 insertions(+), 41 deletions(-) (limited to 'src/main/scala/cc') diff --git a/src/main/scala/cc/spray/json/CollectionFormats.scala b/src/main/scala/cc/spray/json/CollectionFormats.scala index a17c43f..c6c3403 100644 --- a/src/main/scala/cc/spray/json/CollectionFormats.scala +++ b/src/main/scala/cc/spray/json/CollectionFormats.scala @@ -47,15 +47,16 @@ trait CollectionFormats { */ implicit def mapFormat[K :JsonFormat, V :JsonFormat] = new RootJsonFormat[Map[K, V]] { def write(m: Map[K, V]) = JsObject { - m.toList.map { t => - t._1.toJson match { - case JsString(x) => JsField(x, t._2.toJson) + m.map { field => + field._1.toJson match { + case JsString(x) => x -> field._2.toJson case x => throw new SerializationException("Map key must be formatted as JsString, not '" + x + "'") } } } def read(value: JsValue) = value match { - case JsObject(fields) => fields.map(field => (JsString(field.name).convertTo[K], field.value.convertTo[V])).toMap + case JsObject(fields) => + fields.map(field => (JsString(field._1).convertTo[K], field._2.convertTo[V])) (collection.breakOut) case x => throw new DeserializationException("Expected Map as JsObject, but got " + x) } } diff --git a/src/main/scala/cc/spray/json/CompactPrinter.scala b/src/main/scala/cc/spray/json/CompactPrinter.scala index 329c08e..467160d 100644 --- a/src/main/scala/cc/spray/json/CompactPrinter.scala +++ b/src/main/scala/cc/spray/json/CompactPrinter.scala @@ -31,12 +31,12 @@ trait CompactPrinter extends JsonPrinter { } } - private def printObject(members: List[JsField], sb: StringBuilder) { + private def printObject(members: Map[String, JsValue], sb: StringBuilder) { sb.append('{') printSeq(members, sb.append(',')) { m => - printString(m.name, sb) + printString(m._1, sb) sb.append(':') - print(m.value, sb) + print(m._2, sb) } sb.append('}') } diff --git a/src/main/scala/cc/spray/json/DeserializationException.scala b/src/main/scala/cc/spray/json/DeserializationException.scala index 283d996..b317a14 100644 --- a/src/main/scala/cc/spray/json/DeserializationException.scala +++ b/src/main/scala/cc/spray/json/DeserializationException.scala @@ -16,4 +16,4 @@ package cc.spray.json -class DeserializationException(msg: String) extends RuntimeException(msg) \ No newline at end of file +class DeserializationException(msg: String, cause: Throwable = null) extends RuntimeException(msg, cause) \ No newline at end of file diff --git a/src/main/scala/cc/spray/json/JsValue.scala b/src/main/scala/cc/spray/json/JsValue.scala index cc1af91..f4dbf91 100644 --- a/src/main/scala/cc/spray/json/JsValue.scala +++ b/src/main/scala/cc/spray/json/JsValue.scala @@ -18,7 +18,9 @@ package cc.spray.json -import collection.mutable.ListBuffer +import collection.mutable.{LinkedHashMap, ListBuffer} +import collection.immutable.ListMap + /** * The general type of a JSON AST node. @@ -37,22 +39,13 @@ sealed trait JsValue { /** * A JSON object. */ -case class JsObject(fields: List[JsField]) extends JsValue { - lazy val asMap: Map[String, JsValue] = { - val b = Map.newBuilder[String, JsValue] - for (JsField(name, value) <- fields) b += ((name, value)) - b.result() - } -} +case class JsObject(fields: Map[String, JsValue]) extends JsValue object JsObject { - def apply(members: JsField*) = new JsObject(members.toList) + // we use a ListMap in order to preserve the field order + def apply(members: JsField*) = new JsObject(ListMap(members: _*)) + def apply(members: List[JsField]) = new JsObject(ListMap(members: _*)) } -/** - * The members/fields of a JSON object. - */ -case class JsField(name: String, value: JsValue) extends JsValue - /** * A JSON array. */ diff --git a/src/main/scala/cc/spray/json/JsonParser.scala b/src/main/scala/cc/spray/json/JsonParser.scala index b93a9a6..21b1d68 100644 --- a/src/main/scala/cc/spray/json/JsonParser.scala +++ b/src/main/scala/cc/spray/json/JsonParser.scala @@ -31,10 +31,10 @@ object JsonParser extends Parser { def Json = rule { WhiteSpace ~ Value ~ EOI } def JsonObject: Rule1[JsObject] = rule { - "{ " ~ zeroOrMore(Pair, separator = ", ") ~ "} " ~~> (JsObject(_)) + "{ " ~ zeroOrMore(Pair, separator = ", ") ~ "} " ~~> (JsObject(_ :_*)) } - def Pair = rule { JsonStringUnwrapped ~ ": " ~ Value ~~> (JsField(_, _)) } + def Pair = rule { JsonStringUnwrapped ~ ": " ~ Value ~~> ((_, _)) } def Value: Rule1[JsValue] = rule { JsonString | JsonNumber | JsonObject | JsonArray | JsonTrue | JsonFalse | JsonNull diff --git a/src/main/scala/cc/spray/json/PrettyPrinter.scala b/src/main/scala/cc/spray/json/PrettyPrinter.scala index 93ac0b6..429c984 100644 --- a/src/main/scala/cc/spray/json/PrettyPrinter.scala +++ b/src/main/scala/cc/spray/json/PrettyPrinter.scala @@ -37,13 +37,13 @@ trait PrettyPrinter extends JsonPrinter { } } - private def printObject(members: List[JsField], sb: StringBuilder, indent: Int) { + private def printObject(members: Map[String, JsValue], sb: StringBuilder, indent: Int) { sb.append("{\n") printSeq(members, sb.append(",\n")) { m => printIndent(sb, indent + Indent) - printString(m.name, sb) + printString(m._1, sb) sb.append(": ") - print(m.value, sb, indent + Indent) + print(m._2, sb, indent + Indent) } sb.append('\n') printIndent(sb, indent) diff --git a/src/main/scala/cc/spray/json/ProductFormats.scala b/src/main/scala/cc/spray/json/ProductFormats.scala index 90c3349..810a6ec 100644 --- a/src/main/scala/cc/spray/json/ProductFormats.scala +++ b/src/main/scala/cc/spray/json/ProductFormats.scala @@ -401,24 +401,24 @@ trait ProductFormats { val value = p.productElement(ix).asInstanceOf[T] writer match { case _: OptionFormat[_] if (value == None) => rest - case _ => JsField(fieldName, writer.write(value)) :: rest + case _ => (fieldName, writer.write(value)) :: rest } } private def fromField[T](value: JsValue, fieldName: String)(implicit reader: JsonReader[T]) = { - @tailrec - def getFrom(fields: List[JsField]): T = { - if (fields.isEmpty) { - if (reader.isInstanceOf[OptionFormat[_]]) None.asInstanceOf[T] - else throw new DeserializationException("Object is missing required member '" + fieldName + "'") - } else if (fields.head.name == fieldName) { - reader.read(fields.head.value) - } else { - getFrom(fields.tail) - } - } value match { - case x: JsObject => getFrom(x.fields) + case x: JsObject => + var fieldFound = false + try { + val fieldValue = x.fields(fieldName) + fieldFound = true + reader.read(fieldValue) + } + catch { + case e: NoSuchElementException if !fieldFound => + if (reader.isInstanceOf[OptionFormat[_]]) None.asInstanceOf[T] + else throw new DeserializationException("Object is missing required member '" + fieldName + "'", e) + } case _ => throw new DeserializationException("Object expected") } } @@ -437,6 +437,6 @@ trait NullOptions extends ProductFormats { 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] - JsField(fieldName, writer.write(value)) :: rest + (fieldName, writer.write(value)) :: rest } } \ No newline at end of file diff --git a/src/main/scala/cc/spray/json/package.scala b/src/main/scala/cc/spray/json/package.scala index ee50ec0..f080312 100644 --- a/src/main/scala/cc/spray/json/package.scala +++ b/src/main/scala/cc/spray/json/package.scala @@ -17,6 +17,8 @@ package cc.spray package object json { + + type JsField = (String, JsValue) def jsonReader[T](implicit reader: JsonReader[T]) = reader def jsonWriter[T](implicit writer: JsonWriter[T]) = writer -- cgit v1.2.3