Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

JSON de-serialization: constructor memoization ignores type parameters #1417

Closed
JustinMullin opened this Issue · 5 comments

5 participants

@JustinMullin

When de-serializing JSON, the memoization logic which maps classes to constructors in net.liftweb.json.Meta ignores type parameters. If a parameterized type is used multiple times during extraction, subsequent lookups for the same (erased) type will return the original constructor, even if different parameters were provided. The following code highlights the issue - the second call to 'read' tries to construct an instance of TypeA instead of TypeB, and throws an exception when it can't find the field 'foo':

import net.liftweb.json.Serialization.read
import net.liftweb.json.DefaultFormats

object JsonParseTest extends App {
  implicit val formats = DefaultFormats

  val jsonA = """ { "data": { "foo": "string" }, "success": true } """
  println(read[Container[TypeA]](jsonA))
  val jsonB = """ { "data": { "bar": "string" }, "success": true } """
  println(read[Container[TypeB]](jsonB))
}

case class TypeA(foo: String)
case class TypeB(bar: String)
case class Container[D](data: D)

And the output:

Container(TypeA(string))
Exception in thread "main" net.liftweb.json.MappingException: No usable value for data
No usable value for foo
Did not find value which can be converted into java.lang.String
    at net.liftweb.json.Meta$.fail(Meta.scala:191)
    at net.liftweb.json.Extraction$.mkValue$1(Extraction.scala:357)
    at net.liftweb.json.Extraction$.build$1(Extraction.scala:317)
    at net.liftweb.json.Extraction$$anonfun$12.apply(Extraction.scala:253)
    at net.liftweb.json.Extraction$$anonfun$12.apply(Extraction.scala:253)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:233)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:233)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
    at scala.collection.immutable.List.foreach(List.scala:76)
    at scala.collection.TraversableLike$class.map(TraversableLike.scala:233)
    at scala.collection.immutable.List.map(List.scala:76)
    at net.liftweb.json.Extraction$.instantiate$1(Extraction.scala:253)
    at net.liftweb.json.Extraction$.newInstance$1(Extraction.scala:286)
    at net.liftweb.json.Extraction$.build$1(Extraction.scala:315)
    at net.liftweb.json.Extraction$.net$liftweb$json$Extraction$$extract0(Extraction.scala:366)
    at net.liftweb.json.Extraction$.net$liftweb$json$Extraction$$extract0(Extraction.scala:199)
    at net.liftweb.json.Extraction$.extract(Extraction.scala:43)
    at net.liftweb.json.JsonAST$JValue.extract(JsonAST.scala:300)
    at net.liftweb.json.Serialization$.read(Serialization.scala:58)
    at jmullin.api.Test$.parse(API.scala:11)
    at jmullin.api.Test$delayedInit$body.apply(API.scala:16)
    at scala.Function0$class.apply$mcV$sp(Function0.scala:34)
    at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
    at scala.App$$anonfun$main$1.apply(App.scala:60)
    at scala.App$$anonfun$main$1.apply(App.scala:60)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
    at scala.collection.immutable.List.foreach(List.scala:76)
    at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:30)
    at scala.App$class.main(App.scala:60)
    at jmullin.api.Test$.main(API.scala:7)
    at jmullin.api.Test.main(API.scala)
Caused by: net.liftweb.json.MappingException: No usable value for foo
Did not find value which can be converted into java.lang.String
    at net.liftweb.json.Meta$.fail(Meta.scala:191)
    at net.liftweb.json.Extraction$.mkValue$1(Extraction.scala:357)
    at net.liftweb.json.Extraction$.build$1(Extraction.scala:317)
    at net.liftweb.json.Extraction$$anonfun$12.apply(Extraction.scala:253)
    at net.liftweb.json.Extraction$$anonfun$12.apply(Extraction.scala:253)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:233)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:233)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
    at scala.collection.immutable.List.foreach(List.scala:76)
    at scala.collection.TraversableLike$class.map(TraversableLike.scala:233)
    at scala.collection.immutable.List.map(List.scala:76)
    at net.liftweb.json.Extraction$.instantiate$1(Extraction.scala:253)
    at net.liftweb.json.Extraction$.newInstance$1(Extraction.scala:286)
    at net.liftweb.json.Extraction$.build$1(Extraction.scala:315)
    at net.liftweb.json.Extraction$.mkValue$1(Extraction.scala:351)
    ... 29 more
Caused by: net.liftweb.json.MappingException: Did not find value which can be converted into java.lang.String
    at net.liftweb.json.Meta$.fail(Meta.scala:191)
    at net.liftweb.json.Extraction$.convert(Extraction.scala:403)
    at net.liftweb.json.Extraction$.build$1(Extraction.scala:314)
    at net.liftweb.json.Extraction$.mkValue$1(Extraction.scala:351)
    ... 42 more

List discussion: https://groups.google.com/d/msg/liftweb/Sdp1tcfoVAA/oOnWqUlEgvgJ

@jonifreeman jonifreeman was assigned
@ogorun

The problem described by test case is indeed solved, but remained in case of more nested type:

object JsonParseTest extends App {
    implicit val formats = DefaultFormats

   val jsonC = """ { "payload": { "data": { "foo": "string" } } } """
   println(read[ContainerB[ContainerA[TypeA]]](jsonA))

}

case class TypeA(foo: String)
case class ContainerA[D](data: D)
case class ContainerB[T](payload: T) 
@Shadowfiend
Owner

If you open a thread on the mailing list someone may have time to look at the issue you're having.

@ogorun

Ok, thank you @Shadowfiend

@cmarxer

@ogorun Can you provide the link to your thread in the mailing list archive? Did you find a solution?
Thanks!

@ogorun

@cmarxer here is the thread https://groups.google.com/forum/#!topic/liftweb/4unVxv__V2U
I make workarounds for now to avoid need in nested type

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.