Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fix type hints when the target type is a parameterized type

Closes #1059
  • Loading branch information...
commit 4d5103aa647ea45495b8a2cb6d274f69f3476321 1 parent 93aaf7c
Joni Freeman authored
View
10 core/json/src/main/scala/net/liftweb/json/Extraction.scala
@@ -262,12 +262,14 @@ object Extraction {
}
}
- def mkWithTypeHint(typeHint: String, fields: List[JField]) = {
+ def mkWithTypeHint(typeHint: String, fields: List[JField], typeInfo: TypeInfo) = {
val obj = JObject(fields)
val deserializer = formats.typeHints.deserialize
if (!deserializer.isDefinedAt(typeHint, obj)) {
val concreteClass = formats.typeHints.classFor(typeHint) getOrElse fail("Do not know how to deserialize '" + typeHint + "'")
- build(obj, mappingOf(concreteClass))
+ val typeArgs = typeInfo.parameterizedType
+ .map(_.getActualTypeArguments.toList.map(Meta.rawClassOf)).getOrElse(Nil)
+ build(obj, mappingOf(concreteClass, typeArgs))
} else deserializer(typeHint, obj)
}
@@ -276,8 +278,8 @@ object Extraction {
if (custom.isDefinedAt(constructor.targetType, json)) custom(constructor.targetType, json)
else json match {
case JNull => null
- case JObject(JField(JsonClass, JString(t)) :: xs) => mkWithTypeHint(t, xs)
- case JField(_, JObject(JField(JsonClass, JString(t)) :: xs)) => mkWithTypeHint(t, xs)
+ case JObject(JField(JsonClass, JString(t)) :: xs) => mkWithTypeHint(t, xs, constructor.targetType)
+ case JField(_, JObject(JField(JsonClass, JString(t)) :: xs)) => mkWithTypeHint(t, xs, constructor.targetType)
case _ => instantiate
}
}
View
7 core/json/src/main/scala/net/liftweb/json/Formats.scala
@@ -169,7 +169,12 @@ trait TypeHints {
.map(th => (th.hintFor(clazz), th.classFor(th.hintFor(clazz)).getOrElse(error("hintFor/classFor not invertible for " + th))))
.sort((x, y) => delta(x._2, clazz) - delta(y._2, clazz) < 0).head._1
- def classFor(hint: String): Option[Class[_]] = hints find (hintFor(_) == hint)
+ def classFor(hint: String): Option[Class[_]] = {
+ def hasClass(h: TypeHints) =
+ util.control.Exception.allCatch opt (h.classFor(hint)) map (_.isDefined) getOrElse(false)
+
+ components find (hasClass) flatMap (_.classFor(hint))
+ }
override def deserialize: PartialFunction[(String, JObject), Any] = components.foldLeft[PartialFunction[(String, JObject),Any]](Map()) {
(result, cur) => result.orElse(cur.deserialize)
View
12 core/json/src/main/scala/net/liftweb/json/Meta.scala
@@ -158,10 +158,13 @@ private[json] object Meta {
else {
mappings.memoize(clazz, t => {
val c = rawClassOf(t)
- val typeInfo =
- if (typeArgs.isEmpty) TypeInfo(c, None)
- else TypeInfo(c, Some(mkParameterizedType(c, typeArgs)))
- Constructor(typeInfo, constructors(t, Set(), None))
+ val (pt, typeInfo) =
+ if (typeArgs.isEmpty) (t, TypeInfo(c, None))
+ else {
+ val t = mkParameterizedType(c, typeArgs)
+ (t, TypeInfo(c, Some(t)))
+ }
+ Constructor(typeInfo, constructors(pt, Set(), None))
})
}
}
@@ -177,6 +180,7 @@ private[json] object Meta {
def getActualTypeArguments = typeArgs.toArray
def getOwnerType = owner
def getRawType = owner
+ override def toString = getOwnerType + "[" + getActualTypeArguments.mkString(",") + "]"
}
private[json] def unmangleName(name: String) =
View
9 core/json/src/test/scala/net/liftweb/json/SerializationBugs.scala
@@ -124,8 +124,17 @@ object SerializationBugs extends Specification {
val str = Serialization.write(MapWithMap(a, b))
read[MapWithMap](str) mustEqual MapWithMap(a, b)
}
+
+ "Either can't be deserialized with type hints" in {
+ implicit val formats = DefaultFormats + FullTypeHints(classOf[Either[_, _]] :: Nil)
+ val x = Eith(Left("hello"))
+ val s = Serialization.write(x)
+ read[Eith](s) mustEqual x
+ }
}
+case class Eith(x: Either[String, Int])
+
case class MapWithMap(a: Map[String, Map[String, Int]], b: Map[String, Int])
case class LongList(xs: List[Num])
Please sign in to comment.
Something went wrong with that request. Please try again.