Extract lift-json to upper bound case class

I spent the last day searching and reading various sites and articles to try to find the answer to this question myself, and I did not find anything that would help. I’m not even sure how this is possible. My problem is that I am trying to parse and retrieve Json Response using lift-json. The answer consists of 4 parts, where the first 3 parts are always the same for each answer to each type of request that I make. The last part varies depending on the type of request, but it will always be a list of some type. I was hoping to do something like this:

abstract class MyObjects case class Apple(id: Int, name: String, color: String) extends MyObjects case class Orange(id: Long, name: String, state: String) extends MyObjects abstract class MyResponse case class Fruits[T <: MyObjects](aisle: Int, bin: Int, hasWhat: Option[List[T]]) 

Where would I like to know what all apples are, I would make a request for it and return a response with a list of apples. When I try to extract this example:

 myJson.extract[Fruits[Apple]] 

I get this error:

 net.liftweb.json.MappingException: do not know how to get type parameter from T at net.liftweb.json.Meta$.fail(Meta.scala:128) at net.liftweb.json.Meta$Reflection$.term$1(Meta.scala:206) at net.liftweb.json.Meta$Reflection$.typeParameters(Meta.scala:220) at net.liftweb.json.Meta$.mkContainer$1(Meta.scala:91) at net.liftweb.json.Meta$.fieldMapping$1(Meta.scala:101) at net.liftweb.json.Meta$.mkContainer$1(Meta.scala:90) at net.liftweb.json.Meta$.fieldMapping$1(Meta.scala:107) at net.liftweb.json.Meta$.toArg$1(Meta.scala:117) at net.liftweb.json.Meta$$anonfun$constructors$1$1$$anonfun$apply$1.apply(Meta.scala:83) at net.liftweb.json.Meta$$anonfun$constructors$1$1$$anonfun$apply$1.apply(Meta.scala:82) at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:... 

I am using lift-json 2.1 and scala 2.8. I have a way around this by specifically creating a case class for each type of response, but I thought I was trying to make it cleaner. Just wanted to know if a) is it even possible? b) if so, what am I doing wrong?

EDIT ... sample application:

 val apples = """{ "aisle" : 1, "bin" : 1, "hasWhat" : [{ "id" : 4, "name" : "Granny", "color" : "green"}, { "id" : 4, "name" : "Fuji", "color" : "red"}] }""" val oranges = """ { "aisle" : 3, "bin" : 2, "hasWhat" : [{ "id" : 2, "name" : "Navel", "state" : "FL" }, { "id" : 2, "name" : "Clementine", "state" : "Spain" }]}""" scala> val aJson = parse(apples) aJson: net.liftweb.json.JsonAST.JValue = JObject(List(JField(aisle,JInt(1)), JField(bin,JInt(1)), JField(hasWhat,JArray(List(JObject(List(JField(id,JInt(4)), JField(name,JString(Granny)), JField(color,JString(green)))), JObject(List(JField(id,JInt(4)), JField(name,JString(Fuji)), JField(color,JString(red))))))))) scala> val oJson = parse(oranges) oJson: net.liftweb.json.JsonAST.JValue = JObject(List(JField(aisle,JInt(3)), JField(bin,JInt(2)), JField(hasWhat,JArray(List(JObject(List(JField(id,JInt(2)), JField(name,JString(Navel)), JField(state,JString(FL))))))))) scala> val doesntWork = aJson.extract[Fruits] doesntWork: org.spin.node.gogrid.objects.Fruits = Fruits(1,1,None) scala> val works = aJson.extract[AFruit] works: org.spin.node.gogrid.objects.AFruit = AFruit(1,1,Some(List(Apple(4,Granny,green), Apple(4,Fuji,red)))) 

I want doesntWork to be how it works, Where:

 case class AFruit(aisle: Int, bin: Int, hasWhat: Option[List[Apple]]) 

Thanks! -newbie

+6
json scala extract lift
source share
1 answer

Retrieving the parameterized case class is not yet supported. One workaround (not sure if this works for your case) is to make Fruits a concrete type and add type information in JSON.

 import net.liftweb.json._ import net.liftweb.json.Extraction._ import net.liftweb.json.JsonAST._ import net.liftweb.json.Printer._ abstract class MyObjects case class Apple(id: Int, name: String, color: String) extends MyObjects case class Orange(id: Long, name: String, state: String) extends MyObjects case class Fruits(aisle: Int, bin: Int, hasWhat: Option[List[MyObjects]]) object Test extends Application { // This configuration adds an extra field for MyObjects to JSON // which tells the real type of a MyObject. implicit val formats = Serialization.formats(FullTypeHints(List(classOf[MyObjects]))) val fs = Fruits(0, 0, Some(List( Apple(1, "Granny Smith", "green"), Apple(2, "Grenade", "red")))) val json = decompose(fs) println(pretty(render(json))) assert (json.extract[Fruits] == fs) } 

What prints:

 { "aisle":0, "bin":0, "hasWhat":[{ "jsonClass":"Apple", "id":1, "name":"Granny Smith", "color":"green" },{ "jsonClass":"Apple", "id":2, "name":"Grenade", "color":"red" }] } 
+8
source share

All Articles