views:

121

answers:

1

Say I'd like to implement something like this:

def serialize( list: List[_] ) : Node = {
  <list>
  { for ( item <- list ) yield serializeItem(item) }
  </list>
}

def deserialize( node : Node ) : List[_] = {
  // ?
}

How do I get the type of the List, e.g. T in List[T] so I can write that out? Or do I need it? How can I instantiate the list in deserialize?

+1  A: 

Is this close to what you're looking for? Note that it only will serialize homogenous lists.

package example

import scala.xml.{Node,Text}

object App extends Application {
  import Xerialize._

  val x = List(List(1,2),List(2,3,4),List(6))

  println(toXml(x))
  println(fromXml(toXml(x)))

  val z = List(Person("Joe",33),Person("Bob",44))
  println(toXml(z))
  println(fromXml(toXml(z)))
}

object Xerialize {
  def n(node: Node) = node // force to Node, better way?

  case class Person(name: String, age: Int)

  def toXml[T <% Node](t: T): Node = n(t)
  def fromXml(node: Node):Any = node match {

    case <list>{e@_*}</list> => {
      e.toList map { fromXml(_) }
    }

    case <int>{i}</int> => {
      i.text.toInt
    }

    case <person><name>{n}</name><age>{a}</age></person> => {
      Person(n.text,a.text.toInt)
    }

    case _ => {
      throw new RuntimeException("match errror")
    }
  }


  implicit def listToXml[T <% Node](l: List[T]): Node = {
    <list>{ l map { n(_) } }</list>
  }
  implicit def personToXml(p: Person): Node = {
    <person><name>{p.name}</name><age>{p.age}</age></person>
  }
  implicit def intToXml(i: Int): Node = <int>{ i.toString }</int>
}
Mitch Blevins
Yeah, that works for List.. Will it work for any type I choose? The part I am stuck on is the instantiation of the type. It looks like that problem is avoided for List[T] using the toList method. What about a user created class like Foobar[T]?
Alex Black
Notice that the code above creates a List[Any], and the construct toXml(fromXml(toXml(x))) would be disallowed by the compiler. Analogously, you would need to create a Foobar[Any] in the case clause of the deserialization (fromXML).
Mitch Blevins
It almost seems like you want a (Node)=>T function that knows at compile-time the type T that would be generated based on the runtime value of the Node... like a time machine. Would you settle for a return type specified at the call-site? (e.g. - fromXML[List[Int]](node) // throws error if node doesn't actually produce a List[Int])
Mitch Blevins
Almost like a time machine, heh. Yeah specified at the call-site sounds fine. But I was actually think of trying to find a way to serialize the type of T, and then deserialize it so fromXml would know it, no time travel involved!
Alex Black