summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias <mathias@spray.io>2014-10-28 13:23:35 +0100
committerMathias <mathias@spray.io>2014-10-28 13:23:35 +0100
commitef6d8a21849a97cdfc63c5cb740dd55f24807a48 (patch)
treef5a6970b0643d9fe2846b444c96d194476969654
parentc3bd8fe437f422e1314a1a2ecd45c1d8f16facaa (diff)
downloadspray-json-ef6d8a21849a97cdfc63c5cb740dd55f24807a48.tar.gz
spray-json-ef6d8a21849a97cdfc63c5cb740dd55f24807a48.tar.bz2
spray-json-ef6d8a21849a97cdfc63c5cb740dd55f24807a48.zip
Add member name unmangling to ProductFormats, fixes #120
-rw-r--r--src/main/scala/spray/json/ProductFormats.scala27
-rw-r--r--src/test/scala/spray/json/ProductFormatsSpec.scala13
2 files changed, 39 insertions, 1 deletions
diff --git a/src/main/scala/spray/json/ProductFormats.scala b/src/main/scala/spray/json/ProductFormats.scala
index 5f5a9f4..39d5300 100644
--- a/src/main/scala/spray/json/ProductFormats.scala
+++ b/src/main/scala/spray/json/ProductFormats.scala
@@ -78,12 +78,37 @@ trait ProductFormats extends ProductFormatsInstances {
sys.error("Case class " + clazz.getName + " declares additional fields")
if (fields.zip(copyDefaultMethods).exists { case (f, m) => f.getType != m.getReturnType })
sys.error("Cannot determine field order of case class " + clazz.getName)
- fields.map(_.getName)
+ fields.map(f => ProductFormats.unmangle(f.getName))
} catch {
case NonFatal(ex) => throw new RuntimeException("Cannot automatically determine case class field names and order " +
"for '" + clazz.getName + "', please use the 'jsonFormat' overload with explicit field name specification", ex)
}
}
+
+}
+
+object ProductFormats {
+ private val operators = Map(
+ "$eq" -> "=",
+ "$greater" -> ">",
+ "$less" -> "<",
+ "$plus" -> "+",
+ "$minus" -> "-",
+ "$times" -> "*",
+ "$div" -> "/",
+ "$bang" -> "!",
+ "$at" -> "@",
+ "$hash" -> "#",
+ "$percent" -> "%",
+ "$up" -> "^",
+ "$amp" -> "&",
+ "$tilde" -> "~",
+ "$qmark" -> "?",
+ "$bar" -> "|")
+
+ private def unmangle(name: String) = operators.foldLeft(name) { case (n, (mangled, unmangled)) =>
+ if (n.indexOf(mangled) >= 0) n.replace(mangled, unmangled) else n
+ }
}
/**
diff --git a/src/test/scala/spray/json/ProductFormatsSpec.scala b/src/test/scala/spray/json/ProductFormatsSpec.scala
index c4bb489..a290604 100644
--- a/src/test/scala/spray/json/ProductFormatsSpec.scala
+++ b/src/test/scala/spray/json/ProductFormatsSpec.scala
@@ -28,6 +28,7 @@ class ProductFormatsSpec extends Specification {
}
@SerialVersionUID(1L) // SerialVersionUID adds a static field to the case class
case class TestStatic(a: Int, b: Option[Double])
+ case class TestMangled(`foo-bar!`: Int)
trait TestProtocol {
this: DefaultJsonProtocol =>
@@ -36,6 +37,7 @@ class ProductFormatsSpec extends Specification {
implicit def test3Format[A: JsonFormat, B: JsonFormat] = jsonFormat2(Test3.apply[A, B])
implicit def testTransientFormat = jsonFormat2(TestTransient)
implicit def testStaticFormat = jsonFormat2(TestStatic)
+ implicit def testMangledFormat = jsonFormat1(TestMangled)
}
object TestProtocol1 extends DefaultJsonProtocol with TestProtocol
object TestProtocol2 extends DefaultJsonProtocol with TestProtocol with NullOptions
@@ -181,4 +183,15 @@ class ProductFormatsSpec extends Specification {
JsNull.convertTo[Test0] must throwA(new DeserializationException("Object expected"))
)
}
+
+ "A JsonFormat created with `jsonFormat`, for a case class with mangled-name members," should {
+ import TestProtocol1._
+ val json = "{\"foo-bar!\":42}"
+ "produce the correct JSON" in {
+ TestMangled(42).toJson.compactPrint === json
+ }
+ "convert a JsObject to the respective case class instance" in {
+ json.parseJson.convertTo[TestMangled] === TestMangled(42)
+ }
+ }
}