1

Ok, firstly I am new to posting questions here, so go easy on me.

I feel like I have scowered the interwebs to figure this out, and I sure must be slow because I just cant get it right - I know this should be simple.

I have a class:

class Produce extends LongKeyedMapper[Produce] with IdPK {
      def getSingleton = Produce
      object producetype extends MappedString(this,20)
      object name extends MappedString(this,20)
      object description extends MappedString(this,255)

    }

The object has a few helper methods and some other things I have pieced together to try to get this to work:

object Produce extends Produce with LongKeyedMetaMapper[Produce] {
    private implicit val formats = net.liftweb.json.DefaultFormats
    override def fieldOrder = List(producetype, name, description)

    def search(str: String): List[Produce] = {
    val strLC = str.toLowerCase()
    Produce.findAll(By(Produce.producetype, strLC))
    }

    implicit def toJson(item: Produce): JValue = Extraction.decompose(item)
    implicit def toJson(items: List[Produce]): JValue = Extraction.decompose(items)

}

my rest service is doing the basic stuff and is matching with this:

serve( "api" / "item" prefix {
    case "search" :: q JsonGet _ =>
      (for {
        searchString <- q ::: S.params("q")
        item <- Produce.search(searchString)
      } yield item): JValue
  })

So to my delight, it worked, i got it matching.. and returning Json, the problem is: Let's say I have 3 rows in the DB with producetype: a, if I call the service with 'a' it returns:

[{

},{

},{

}]

So it is returning, it just isn't serializing any of the data... I have tried overloading unapply methods and trying to figure out if case classes could help me out - but it isn't clicking n my feeble mind. Any help?

mikemwalsh
  • 35
  • 3
  • Right after posting this I got it working, but apparently my comment didn't post when I followed up. Sorry. I was able to fix it by doing `implicit def toJson(item: Produce): JValue = ("Produce item"-> ("name" -> item.name.toString) ~ ("description" -> item.description.toString) ) implicit def toJson(items: List[Produce]): JValue = ("Produce items" -> items.map(i => toJson(i))) ` Hopefully this helps someone. – mikemwalsh Feb 03 '12 at 01:36

2 Answers2

2

I think you may need to add a wrapper. It seems mappers cannot handle this without a little help, although this would make sense to have in Lift - with all the other great REST and Json functions.

Something like the following and then swap between the Wrapper and the Mapper in your REST calls:

case class ProduceWrapper(producetype: String, name: String, description: String)

object ProduceWrapper {

  private implicit val formats = net.liftweb.json.DefaultFormats

  def apply(in: JValue): Box[ProduceWrapper] = Helpers.tryo{in.extract[ProduceWrapper]}

  def unapply(in: JValue): Option[ProduceWrapper] = apply(in)

  def unapply(in: Any): Option[(String, String, String)] = {
     in match {
        case i: ProduceWrapper => Some((i.producetype, i.name, i.description))
        case _ => None
     }
  }

  implicit def toJson(item: ProduceWrapper): JValue = Extraction.decompose(item)
  implicit def toJson(items: List[ProduceWrapper]): JValue = Extraction.decompose(items)

}

In the REST class:

serve( "api" / "produce" prefix {
    case Nil JsonPut ProduceWrapper(item) -> _ => Produce.add(item): JValue
}

And then in the Produce class:

  def add(item: ProduceWrapper): ProduceWrapper = {
   Produce.create.name(item.name).description(item.description).save
   item
  }
UStudios
  • 21
  • 3
0

I believe that Lift's json support requires case classes and so probably doesn't work with Mapped objects.

You could try creating a case class constructed with the fields of Produce in the toJson methods.

I also found this which looks helpful: http://scala-programming-language.1934581.n4.nabble.com/Mapper-lt-gt-JObject-bridge-td1981293.html

Channing Walton
  • 3,977
  • 1
  • 30
  • 59