serializing and deserializing a json object through Lift-JSON

1,277 views
Skip to first unread message

Ali

unread,
Feb 10, 2010, 11:42:12 AM2/10/10
to Lift
Dear All,
I am wondering would you please tell me how can I use lift-json (2.0
snapshots) to serialize and deserialize the following scala case
classes.

case class Plan( plan:Option[Action] )
case class Game( game:Map[String,Plan])
case class Action(id:Int, subAction : Option[Action])


val game = new Game(Map("a"->new Plan(new Some(new Action(1,None)))))
implicit val formats = net.liftweb.json.DefaultFormats

game must beEqualTo( Serialization.read[Game]
(Serialization.write(game)))

Test fails.

Cheers,
-A

Justin Reardon

unread,
Feb 10, 2010, 12:49:15 PM2/10/10
to lif...@googlegroups.com
Sometimes the serialization code needs a helping hand, using:

implicit val format = Serialization.formats(ShortTypeHints(List(classOf[Plan], classOf[Action], classOf[Game])))

instead of the defaults makes it work here.

Cheers,
Justin Reardon

> --
> You received this message because you are subscribed to the Google Groups "Lift" group.
> To post to this group, send email to lif...@googlegroups.com.
> To unsubscribe from this group, send email to liftweb+u...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
>

Joni Freeman

unread,
Feb 11, 2010, 2:44:36 AM2/11/10
to Lift
Hi,

Type hints should not be needed in this case since the Map is not used
in a polymorphic way. But the work-around Justin showed should work.
Actually it seems that it is enough to put type info just to Action to
make serialization work:

implicit val format =
Serialization.formats(ShortTypeHints(List(classOf[Action]))

Anyway, I added a ticket for this defect:
http://www.assembla.com/spaces/liftweb/tickets/341-Type-hints-are-needed-in-JSON-serializization-for-non-polymorphic-Map-

Cheers Joni

Ali

unread,
Feb 11, 2010, 5:09:14 AM2/11/10
to Lift

Thanks guys, Actually my problem is still there, It looks like lift-
json doesn't support scala-arrays.

case class Plan( leftOperand:Option[Action],
operator:Option[String],
rightOperand:Option[Action])

case class Game(buy:Map[String,Plan])

case class Action(
functionName:String,
symbol:String,
inParams: Array[Number] ,
subOperand : Option[Action])

val game = new Game(Map("a"->new Plan(Some(new
Action("f1","s",Array(),None)),Some("A"),Some(new
Action("f1","s",Array(0,1,2),None)))))


implicit val format =
Serialization.formats(ShortTypeHints(List(classOf[Plan],
classOf[Action], classOf[Game])))

println(Serialization.write(game))

The output is:

{"jsonClass":"Game","buy":{"a":{"jsonClass":"Plan","rightOperand":
{"jsonClass":"Action","symbol":"s","functionName":"f1"},"operator":"A","leftOperand":
{"jsonClass":"Action","symbol":"s","functionName":"f1"}}}}

which is not correct (missing the inParams field from the action
class).

I appreciate your comment,

Cheers,
-A


On Feb 11, 8:44 am, Joni Freeman <freeman.j...@gmail.com> wrote:
> Hi,
>
> Type hints should not be needed in this case since the Map is not used
> in a polymorphic way. But the work-around Justin showed should work.
> Actually it seems that it is enough to put type info just to Action to
> make serialization work:
>
>     implicit val format =
> Serialization.formats(ShortTypeHints(List(classOf[Action]))
>

> Anyway, I added a ticket for this defect:http://www.assembla.com/spaces/liftweb/tickets/341-Type-hints-are-nee...

Joni Freeman

unread,
Feb 11, 2010, 5:41:04 AM2/11/10
to Lift
Hi,

Yes, that's true. Arrays are not yet supported. Just Option, List and
Map. Adding array support (which should be trivial) is on TODO list
though.

Cheers Joni

Joni Freeman

unread,
Feb 14, 2010, 11:32:40 AM2/14/10
to Lift
Hi,

I just added Array support and fixed the bug 341. It is now waiting on
review board for others to comment. You can checkout branch
'joni_issue_341' if you want to try it immediately.

This test case now passes (Please note the verbose assertions in
second test case. Those are needed because scala.Array's equals is
reference comparison, Array(1, 2) == Array(1, 2) -> false):

http://github.com/dpp/liftweb/blob/joni_issue_341/framework/lift-base/lift-json/src/test/scala/net/liftweb/json/SerializationBugs.scala

Cheers Joni

On Feb 11, 12:09 pm, Ali <saleh...@gmail.com> wrote:

> Thanks guys, Actually my problem is still there, It looks like lift-jsondoesn't support scala-arrays.

Ali

unread,
Feb 17, 2010, 6:45:04 AM2/17/10
to Lift
Hi,
I just updated to the latest lift-json snapshot and tried to
serialize one of my case classes:
The output starts with:

{
"bitmap$0":0,
"sell_exp":null,
"buy_exp":null,
"x$3":null,
"sell_exp_str":null,
"buy_exp_str":null,
"x$2":null,
"sell_vars":null,
"buy_vars":null,
"x$1":null,

For your information, things like buy_exp, buy_vars,... are declared
as lazy val inside the body of the case class.
I have two questions:
- Is it possible to configure lift-json so It would not serialize
internal variables ? case class X(a:Int) {lazy val y = a}
- Is it possible to generate a clean json output without x$0 or bitmap
$0,... entries ?

Thanks,
-A

On Feb 14, 5:32 pm, Joni Freeman <freeman.j...@gmail.com> wrote:
> Hi,
>

> I just added Array support and fixed the bug 341. It is now waiting on
> review board for others to comment. You can checkout branch
> 'joni_issue_341' if you want to try it immediately.
>
> This test case now passes (Please note the verbose assertions in
> second test case. Those are needed because scala.Array's equals is
> reference comparison, Array(1, 2) == Array(1, 2) -> false):
>

> http://github.com/dpp/liftweb/blob/joni_issue_341/framework/lift-base...

Joni Freeman

unread,
Feb 17, 2010, 7:23:35 AM2/17/10
to Lift
Hi Ali,

I added a ticket for this:
http://www.assembla.com/spaces/liftweb/tickets/352-do-not-serialize-the-internal-state-of-a-case-class-(json)

Meanwhile, you can cleanup the serialized JSON for instance by using
'remove' function. Something like:

val cleanJson = decompose(x) remove {
case JField(n, _) if n.contains('$') => true
case _ => false
}
compact(render(cleanJson))

Cheers Joni

Ali

unread,
Feb 17, 2010, 8:27:38 AM2/17/10
to Lift
Thank you :)
-A

On Feb 17, 1:23 pm, Joni Freeman <freeman.j...@gmail.com> wrote:
> Hi Ali,
>

> I added a ticket for this:http://www.assembla.com/spaces/liftweb/tickets/352-do-not-serialize-t...)

Joni Freeman

unread,
Feb 17, 2010, 1:04:10 PM2/17/10
to Lift
Fix is in master now. Should be in next snapshot build too.

Cheers Joni

Ali

unread,
Feb 19, 2010, 5:16:50 PM2/19/10
to Lift
Hi,
I am wondering, could you please let me know what is wrong in the
following code:

case class X(vv:String)
val sample = new X("A")

implicit val formats = net.liftweb.json.DefaultFormats

import net.liftweb.json.JsonAST._
import net.liftweb.json.Extraction._
import net.liftweb.json.Printer._

def from(in:String):X=net.liftweb.json.Serialization.read[X](in)
def to(in:X):String=compact(render(decompose(in)))

val sample2=from(to(sample))
sample2 must_== sample

I am getting java.util.NoSuchElementException: key not found: $outer

Thanks,
-A

Joni Freeman

unread,
Feb 19, 2010, 6:06:30 PM2/19/10
to Lift
Hi,

Can't reproduce that. Those lines should work just fine. From which
line do you get that exception (please attach full stack trace too)?

Cheers Joni

Joni Freeman

unread,
Feb 19, 2010, 6:10:46 PM2/19/10
to Lift
Is X perhaps an inner class? Inner class has an implicit reference to
outer instance. Serializing those is not supported.

If so, please move definition of X outside of class.

Cheers Joni

On Feb 20, 12:16 am, Ali <saleh...@gmail.com> wrote:

Ali

unread,
Feb 20, 2010, 1:13:46 AM2/20/10
to Lift
Thanks for your reply. Actually I was trying to build an exception I
am receiving in our product.

case class X(yy:Y)
case class Y(ss:String)

def from(in:String):X={


implicit val formats = net.liftweb.json.DefaultFormats
import net.liftweb.json.JsonAST._
import net.liftweb.json.Extraction._
import net.liftweb.json.Printer._

net.liftweb.json.Serialization.read[X](in)
}
def to(in:X):String={


implicit val formats = net.liftweb.json.DefaultFormats
import net.liftweb.json.JsonAST._
import net.liftweb.json.Extraction._
import net.liftweb.json.Printer._

compact(render(decompose(in)))
}

val sample = new X(null)
val sample2=from(to(sample))

and I am getting,
net.liftweb.json.MappingException: Did not find value which can
be converted into java.lang.String
at net.liftweb.json.Meta$.fail(Meta.scala:99)
at net.liftweb.json.Extraction$.convert(Extraction.scala:280)
at net.liftweb.json.Extraction$.build$1(Extraction.scala:216)
at net.liftweb.json.Extraction$$anonfun$newInstance
$1$1.apply(Extraction.scala:199)
at net.liftweb.json.Extraction$$anonfun$newInstance
$1$1.apply(Extraction.scala:199)
at scala.List.map(List.scala:812)

I appreciate your comment,

Thanks,
-A

Joni Freeman

unread,
Feb 20, 2010, 4:39:52 AM2/20/10
to Lift
Ok, this was yet another bug in serialization code. It is now fixed
and should be in next snapshot build. Deserializing null values were
not supported. Note a recommended way is to use Option for optional
values. This would've worked:

case class X(yy: Option[Y])
case class Y(ss: String)

from(to(X(None)))

It makes me a bit sad that both Scala and JSON support null values...

Cheers Joni

Message has been deleted

Ali

unread,
Feb 20, 2010, 5:10:44 AM2/20/10
to Lift
Thank you :)

-A

Ross Mellgren

unread,
Feb 20, 2010, 12:13:31 PM2/20/10
to lif...@googlegroups.com
http://www.assembla.com/spaces/liftweb/tickets/358

It's already been pushed to master so is probably in 2.0-SNAPSHOT.

-Ross

On Feb 20, 2010, at 5:09 AM, Ali wrote:

Hi Joni,
Would you please also post the ticket url so I can track it.

Thank you again,
-A
Reply all
Reply to author
Forward
0 new messages