lift-json extraction woes

221 views
Skip to first unread message

Colin Bester

unread,
Aug 14, 2013, 12:11:17 PM8/14/13
to lif...@googlegroups.com
I am using scala 2.10.2 and lift-json_2.10 V 2.5.1 and have reverted to test code going back to basic examples.

My issue is extracting json object into scala class - while there is a lot out there on this topic some of it is updated and some don't apply. My issue is that I am getting an unexpected exception and was wondering if anyone could assist or provide a working example snippet using versions stated above. 

Code is so simple I thought it easiest to simply paste here.

package com.besterdesigns.mandrill

import net.liftweb.json._
import net.liftweb.json.JsonAST._

object App {

  def main(args: Array[String]) {
    implicit val formats = DefaultFormats     
//      Serialization.formats(FullTypeHints(List(classOf[Holder])))
//      Serialization.formats(FullTypeHints(List(classOf[AnyRef])))

    case class Holder(values: Map[String, Any])
    case class Person(name: String, age: Int)
    case class Dog(owner: Person, name: String)

    val vals = Map("p" -> Person("joe doe", 32),
                   "dog" -> Dog(Person("ann", 12), "pluto"))
                   
    val myjson = Extraction.decompose(Holder(vals))

    println("myson " + myjson)
    val h = myjson.extract[Holder]
  }
}

The exception I am getting is:
Exception in thread "main" net.liftweb.json.MappingException: unknown error
at net.liftweb.json.Extraction$.extract(Extraction.scala:46)
at net.liftweb.json.JsonAST$JValue.extract(JsonAST.scala:300)
at com.besterdesigns.mandrill.App$.main(App.scala:73)
at com.besterdesigns.mandrill.App.main(App.scala)
Caused by: java.lang.NullPointerException
at scala.tools.scalap.scalax.rules.scalasig.ByteCode$.forClass(ClassFileParser.scala:16)
at scala.tools.scalap.scalax.rules.scalasig.ScalaSigParser$.parse(ScalaSig.scala:49)
at net.liftweb.json.ScalaSigReader$.net$liftweb$json$ScalaSigReader$$findScalaSig(ScalaSig.scala:118)
at net.liftweb.json.ScalaSigReader$$anonfun$net$liftweb$json$ScalaSigReader$$findScalaSig$1.apply(ScalaSig.scala:118)
at net.liftweb.json.ScalaSigReader$$anonfun$net$liftweb$json$ScalaSigReader$$findScalaSig$1.apply(ScalaSig.scala:118)
at scala.Option.orElse(Option.scala:257)
at net.liftweb.json.ScalaSigReader$.net$liftweb$json$ScalaSigReader$$findScalaSig(ScalaSig.scala:118)
at net.liftweb.json.ScalaSigReader$.findClass(ScalaSig.scala:40)
at net.liftweb.json.ScalaSigReader$.readConstructor(ScalaSig.scala:24)
at net.liftweb.json.Meta$Reflection$.term$1(Meta.scala:277)
at net.liftweb.json.Meta$Reflection$.typeParameters(Meta.scala:295)
at net.liftweb.json.Meta$.mkContainer$1(Meta.scala:108)
at net.liftweb.json.Meta$.fieldMapping$1(Meta.scala:137)
at net.liftweb.json.Meta$.net$liftweb$json$Meta$$toArg$1(Meta.scala:155)
at net.liftweb.json.Meta$$anonfun$net$liftweb$json$Meta$$constructors$1$1$$anonfun$apply$1.apply(Meta.scala:99)
at net.liftweb.json.Meta$$anonfun$net$liftweb$json$Meta$$constructors$1$1$$anonfun$apply$1.apply(Meta.scala:98)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.immutable.List.foreach(List.scala:318)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:244)
at scala.collection.AbstractTraversable.map(Traversable.scala:105)
at net.liftweb.json.Meta$$anonfun$net$liftweb$json$Meta$$constructors$1$1.apply(Meta.scala:98)
at net.liftweb.json.Meta$$anonfun$net$liftweb$json$Meta$$constructors$1$1.apply(Meta.scala:97)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.immutable.List.foreach(List.scala:318)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:244)
at scala.collection.AbstractTraversable.map(Traversable.scala:105)
at net.liftweb.json.Meta$.net$liftweb$json$Meta$$constructors$1(Meta.scala:97)
at net.liftweb.json.Meta$$anonfun$mappingOf$1.apply(Meta.scala:169)
at net.liftweb.json.Meta$$anonfun$mappingOf$1.apply(Meta.scala:161)
at net.liftweb.json.Meta$Memo.memoize(Meta.scala:199)
at net.liftweb.json.Meta$.mappingOf(Meta.scala:161)
at net.liftweb.json.Extraction$.net$liftweb$json$Extraction$$mkMapping$1(Extraction.scala:194)
at net.liftweb.json.Extraction$.net$liftweb$json$Extraction$$extract0(Extraction.scala:199)
at net.liftweb.json.Extraction$.extract(Extraction.scala:43)
... 3 more

I am not in the habit of wasting folks time and I know I am going to kick myself when I see what I'm doing wrong.

Appreciate your help
Colin

Antonio Salazar Cardozo

unread,
Aug 14, 2013, 12:22:06 PM8/14/13
to lif...@googlegroups.com
Hey Colin,
There's typically been some weirdness associated with case classes declared in strange places (it used to be the scala console that gave troubles). As such, I'd say can you see what happens if you move the case classes to the top level instead of being declared in the singleton?
Thanks,
Antonio

Antonio Salazar Cardozo

unread,
Aug 14, 2013, 12:24:06 PM8/14/13
to lif...@googlegroups.com
Another, perhaps more likely, possibility is that you need to include the type hints for Person and Dog, otherwise lift-json will may to find the constructor parameters for Any, which of course doesn't work quite as expected.
Thanks,
Antonio

Colin Bester

unread,
Aug 14, 2013, 5:09:07 PM8/14/13
to lif...@googlegroups.com
Placing the case classes at top level changed the error message to expected error message of type not found, so while weird at least indicates that it's now down to TypeHints.

Colin Bester

unread,
Aug 14, 2013, 5:44:38 PM8/14/13
to lif...@googlegroups.com
Hmm, seems my response disappeared.

Problem with TypeHints is that they add jsonClass element to json output which breaks the interface I need to interface to. I'm going to have to rethink this. lift-json may well not be the right tool in the toolbox for this one.

Diego Medina

unread,
Aug 14, 2013, 10:04:49 PM8/14/13
to Lift
If the resulting json doesn't look the way you want it, you can always use transform to change it in a way that will fit your interface.

This page has some info on it (in case you haven't seen it before)


Thanks


--
--
Lift, the simply functional web framework: http://liftweb.net
Code: http://github.com/lift
Discussion: http://groups.google.com/group/liftweb
Stuck? Help us help you: https://www.assembla.com/wiki/show/liftweb/Posting_example_code
 
---
You received this message because you are subscribed to the Google Groups "Lift" group.
To unsubscribe from this group and stop receiving emails from it, send an email to liftweb+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



--
Diego Medina
Lift/Scala Developer
di...@fmpwizard.com
http://fmpwizard.telegr.am

Colin Bester

unread,
Aug 14, 2013, 10:26:13 PM8/14/13
to lif...@googlegroups.com
Thanks Diego I will take a look at link provided. Although issue as I see it is that in order for lift-json to extract to polymorphic class it needs the hints to be on the json packet - is this correct assumption?

Sent from my iPhone
You received this message because you are subscribed to a topic in the Google Groups "Lift" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/liftweb/6jT2LZHvS3s/unsubscribe.
To unsubscribe from this group and all its topics, send an email to liftweb+u...@googlegroups.com.

Diego Medina

unread,
Aug 14, 2013, 11:51:00 PM8/14/13
to Lift
no, you can define your own hint, that link has some info and then Matt gave some info here

Thanks

  Diego


Colin Bester

unread,
Aug 16, 2013, 8:43:30 AM8/16/13
to lif...@googlegroups.com
I thought I'd define problem a little clearer in case I was confusing the issue.

I am wanting to read a json string which is predefined and over which I don't have control (an existing system). An example of json string (nesting has been reduced) is:

{"name":"atest","data":{"rcpt":"user1","values":{"akey1":"astring","akey2":123}}}

where the 'values' tuple has format of (String, Int or String) and there is no predefined order.


My testing code is:
package com.besterdesigns.json

import net.liftweb.json.{DefaultFormats, ShortTypeHints, parse}

object App {
  case class RecipientData(val rcpt: String, val values: Map[String, Any])
  case class Root(name: String, data: RecipientData)

  def main(args: Array[String]) {
    implicit val formats = DefaultFormats.withHints(ShortTypeHints(classOf[Root]::classOf[RecipientData]::Nil))

    //Example of incoming json string - format is fixed
    val jsonStr = """{"name":"atest","data":{"rcpt":"user1","values":{"akey1":"astring","akey2":123}}}"""
      
    val json = parse(jsonStr)  
    println("incoming json string -> "+jsonStr)
    println("parsed json object -> "+json)
    
    val obj = json.extract[Root]
    println("Root obj -> " + obj.data.values)
  }
}

In this case I still don't see how TypeHints help as from what I understand TypeHints embed data into the json string so including them in Formats at extraction time won't help - maybe I still misunderstand and am using them incorrectly.

Again, thanks for your time on this

Colin

Antonio Salazar Cardozo

unread,
Aug 19, 2013, 11:09:16 AM8/19/13
to lif...@googlegroups.com
So basically at this point you'll need a set of custom serializers/deserializers. These use pattern matching partial functions, so you can detect whether certain fields are present and instantiate the appropriate class based on that.

If anything is unclear once you've looked into that as a possibility, come and ask any questions you may have and we'll gladly help :)
Thanks,
Antonio

Colin Bester

unread,
Aug 19, 2013, 4:53:06 PM8/19/13
to lif...@googlegroups.com
Thanks Antonio, that's kinda where my thoughts were going. I just need to decide if I am going to write deserializers or just simply parse the json string myself.

Appreciate you all looking/commenting on this.

Cheers
Colin


Reply all
Reply to author
Forward
0 new messages