Skip to content
This repository has been archived by the owner on Jan 15, 2022. It is now read-only.

Commit

Permalink
Fixed fromJSON bug where deserializing Option[_ <: CaseClass] fails b…
Browse files Browse the repository at this point in the history
…y adding redirect to use child type
  • Loading branch information
rktoomey committed Jun 27, 2012
1 parent 8860344 commit afb2914
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 6 deletions.
1 change: 1 addition & 0 deletions notes/1.9.0.markdown
Expand Up @@ -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) - 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, - 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).) create a [custom Salat context](https://github.com/novus/salat/wiki/CustomContext).)
- fixed fromJSON bug deserializing `Option` typed to a case class


4 changes: 4 additions & 0 deletions salat-core/src/main/scala/com/novus/salat/json/ToJValue.scala
Expand Up @@ -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 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.isOid => deserialize(o, field.tf)
case o: JObject if field.tf.isDate || field.tf.isDateTime => 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) case o: JObject => ctx.lookup(if (childType.isDefined) childType.get.symbol.path else field.typeRefType.symbol.path).fromJSON(o)
Expand Down
Expand Up @@ -281,6 +281,7 @@ package in {
Some(mdbo) Some(mdbo)
} }
case mdbo: MongoDBObject => Some(mdbo) case mdbo: MongoDBObject => Some(mdbo)
case cc: CaseClass => Some(cc)
case _ => None case _ => None
} }


Expand All @@ -300,8 +301,9 @@ package in {
trait OptionInjector extends Transformer { trait OptionInjector extends Transformer {
self: Transformer => self: Transformer =>
override def after(value: Any)(implicit ctx: Context): Option[Any] = value match { override def after(value: Any)(implicit ctx: Context): Option[Any] = value match {
case value if value != null => Some(Some(value)) case value @ Some(x) if x != null => Some(value)
case _ => Some(None) case value if value != null => Some(Some(value))
case _ => Some(None)
} }
} }


Expand Down
Expand Up @@ -80,4 +80,5 @@ case class Johan(s: String, d: Double) extends Helge
@Salat @Salat
abstract class Kalle(s: String) abstract class Kalle(s: String)
case class Ludvig(s: String) extends Kalle(s) 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])
19 changes: 16 additions & 3 deletions salat-core/src/test/scala/com/novus/salat/test/json/JsonSpec.scala
Expand Up @@ -33,7 +33,6 @@ import net.liftweb.json.JsonParser.ParseException


class JsonSpec extends Specification with Logging { class JsonSpec extends Specification with Logging {


// TODO: traits and abstract superclasses
// TODO: @Key // TODO: @Key
// TODO: @Ignore // TODO: @Ignore
// TODO: @Persist // TODO: @Persist
Expand All @@ -43,6 +42,8 @@ class JsonSpec extends Specification with Logging {
val ints = List(1, 2, 3) val ints = List(1, 2, 3)
val strings = List("a", "b", "c") val strings = List("a", "b", "c")
val b = Bertil(ints = ints, strings = strings) val b = Bertil(ints = ints, strings = strings)
val g = Gustav(o = Some("OG"))
val n = Niklas(Some(g))


"JSON support" should { "JSON support" should {
"handle converting model objects to JObject" in { "handle converting model objects to JObject" in {
Expand Down Expand Up @@ -135,7 +136,12 @@ class JsonSpec extends Specification with Logging {
} }
"Options" in { "Options" in {
"Some[A]" 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 { "None" in {
grater[Gustav].toCompactJSON(Gustav(o = None)) must_== "{}" grater[Gustav].toCompactJSON(Gustav(o = None)) must_== "{}"
Expand Down Expand Up @@ -246,7 +252,13 @@ class JsonSpec extends Specification with Logging {
} }
"where the model object contains Option fields" in { "where the model object contains Option fields" in {
"Some[A]" 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 { "None" in {
grater[Gustav].fromJSON(JObject(Nil)) must_== Gustav(o = None) grater[Gustav].fromJSON(JObject(Nil)) must_== Gustav(o = None)
Expand Down Expand Up @@ -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"}}""" 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[Adam].fromJSON(adam) must_== a
grater[Bertil].fromJSON("""{"ints":[1,2,3],"strings":["a","b","c"]}""") must_== b 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 { "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}]""" 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}]"""
Expand Down
Expand Up @@ -61,6 +61,7 @@ protected[salat] case class TypeFinder(t: TypeRefType) {
lazy val isBigInt = Types.isBigInt(t.symbol) lazy val isBigInt = Types.isBigInt(t.symbol)
lazy val isLong = TypeMatchers.matches(t, classOf[Long].getName) 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 isOid = TypeMatchers.matches(t, Types.Oid)
lazy val isURL = TypeMatchers.matches(t, classOf[java.net.URL].getName) lazy val isURL = TypeMatchers.matches(t, classOf[java.net.URL].getName)
} }
Expand Down

0 comments on commit afb2914

Please sign in to comment.