Permalink
Browse files

Fixed fromJSON bug where deserializing Option[_ <: CaseClass] fails b…

…y adding redirect to use child type
  • Loading branch information...
1 parent 8860344 commit afb29144bae3b32956e3b5d128ab279bd9fe798c @rktoomey rktoomey committed Jun 27, 2012
View
@@ -3,4 +3,5 @@ Features new in Salat 1.9.0 include:
- Casbah support has been upgraded to [2.3.0](http://notes.implicit.ly/post/25727213706/casbah-2-3-0)
- global `Context` now defaults to When Necessary [type hinting][typehint] using a key of `_typeHint` (To change this default,
create a [custom Salat context](https://github.com/novus/salat/wiki/CustomContext).)
+- fixed fromJSON bug deserializing `Option` typed to a case class
@@ -118,6 +118,10 @@ object FromJValue extends Logging {
}
case notMap => sys.error("FromJValue: expected types for Map but instead got:\n%s".format(notMap))
}
+ case o: JObject if field.tf.isOption && childType.isEmpty => field.typeRefType.typeArgs match {
+ case List(childType: TypeRefType) => apply(j, field, Some(childType))
+ case notOption => sys.error("FromJValue: expected type for Option but instead got:\n%s".format(notOption))
+ }
case o: JObject if field.tf.isOid => deserialize(o, field.tf)
case o: JObject if field.tf.isDate || field.tf.isDateTime => deserialize(o, field.tf)
case o: JObject => ctx.lookup(if (childType.isDefined) childType.get.symbol.path else field.typeRefType.symbol.path).fromJSON(o)
@@ -281,6 +281,7 @@ package in {
Some(mdbo)
}
case mdbo: MongoDBObject => Some(mdbo)
+ case cc: CaseClass => Some(cc)
case _ => None
}
@@ -300,8 +301,9 @@ package in {
trait OptionInjector extends Transformer {
self: Transformer =>
override def after(value: Any)(implicit ctx: Context): Option[Any] = value match {
- case value if value != null => Some(Some(value))
- case _ => Some(None)
+ case value @ Some(x) if x != null => Some(value)
+ case value if value != null => Some(Some(value))
+ case _ => Some(None)
}
}
@@ -80,4 +80,5 @@ case class Johan(s: String, d: Double) extends Helge
@Salat
abstract class Kalle(s: String)
case class Ludvig(s: String) extends Kalle(s)
-case class Martin(s: String, d: Double) extends Kalle(s)
+case class Martin(s: String, d: Double) extends Kalle(s)
+case class Niklas(g: Option[Gustav])
@@ -33,7 +33,6 @@ import net.liftweb.json.JsonParser.ParseException
class JsonSpec extends Specification with Logging {
- // TODO: traits and abstract superclasses
// TODO: @Key
// TODO: @Ignore
// TODO: @Persist
@@ -43,6 +42,8 @@ class JsonSpec extends Specification with Logging {
val ints = List(1, 2, 3)
val strings = List("a", "b", "c")
val b = Bertil(ints = ints, strings = strings)
+ val g = Gustav(o = Some("OG"))
+ val n = Niklas(Some(g))
"JSON support" should {
"handle converting model objects to JObject" in {
@@ -135,7 +136,12 @@ class JsonSpec extends Specification with Logging {
}
"Options" in {
"Some[A]" in {
- grater[Gustav].toPrettyJSON(Gustav(o = Some("OG"))) must /("o" -> "OG")
+ "simple type" in {
+ grater[Gustav].toPrettyJSON(g) must /("o" -> "OG")
+ }
+ "case class" in {
+ grater[Niklas].toPrettyJSON(n) must /("g") */ ("o" -> "OG")
+ }
}
"None" in {
grater[Gustav].toCompactJSON(Gustav(o = None)) must_== "{}"
@@ -246,7 +252,13 @@ class JsonSpec extends Specification with Logging {
}
"where the model object contains Option fields" in {
"Some[A]" in {
- grater[Gustav].fromJSON(JObject(JField("o", JString("OG")) :: Nil)) must_== Gustav(o = Some("OG"))
+ "simple type" in {
+ grater[Gustav].fromJSON(JObject(JField("o", JString("OG")) :: Nil)) must_== g
+ }
+ "case class" in {
+ grater[Niklas].fromJSON(JObject(
+ JField("g", JObject(JField("o", JString("OG")) :: Nil)) :: Nil)) must_== n
+ }
}
"None" in {
grater[Gustav].fromJSON(JObject(Nil)) must_== Gustav(o = None)
@@ -282,6 +294,7 @@ class JsonSpec extends Specification with Logging {
val adam = """{"a":"string","b":99,"c":3.14,"d":false,"e":"2011-12-28T14:37:56.008Z","u":"http://www.typesafe.com","o":{"$oid":"4fd0bead4ceab231e6f3220b"}}"""
grater[Adam].fromJSON(adam) must_== a
grater[Bertil].fromJSON("""{"ints":[1,2,3],"strings":["a","b","c"]}""") must_== b
+ grater[Niklas].fromJSON("""{"g":{"o":"OG"}}""") must_== n
}
"a string that can be parsed to a JSON array" in {
val arr = """[{"_t":"com.novus.salat.test.json.Martin","s":"one","d":1.1},{"_t":"com.novus.salat.test.json.Martin","s":"two","d":2.2},{"_t":"com.novus.salat.test.json.Martin","s":"three","d":3.3}]"""
@@ -61,6 +61,7 @@ protected[salat] case class TypeFinder(t: TypeRefType) {
lazy val isBigInt = Types.isBigInt(t.symbol)
lazy val isLong = TypeMatchers.matches(t, classOf[Long].getName)
+ lazy val isOption = TypeMatchers.matches(t, Types.Option)
lazy val isOid = TypeMatchers.matches(t, Types.Oid)
lazy val isURL = TypeMatchers.matches(t, classOf[java.net.URL].getName)
}

0 comments on commit afb2914

Please sign in to comment.