sjrd / scala-js-pickling

Pickling for Scala.js
40 stars 10 forks source link

Including picklers for collections #2

Closed antonkulaga closed 6 years ago

antonkulaga commented 10 years ago

I think generic picklers for collections will be very useful because in most of the cases users pass collections. For instance for list something like:

class GenericConsPickler[T] extends Pickler[::[T]] {
  def pickle[P](value: ::[T])(implicit registry: PicklerRegistry,
                              builder: PBuilder[P]): P = {
    builder.makeArray(value.map(registry.pickle(_)): _*)
  }
}

class GenericConsUnpickler[T] extends Unpickler[::[T]] {
  def unpickle[P](pickle: P)(implicit registry: PicklerRegistry,
                             reader: PReader[P]): ::[T] = {
    val len = reader.readArrayLength(pickle)
    assert(len > 0)
    ((0 until len).toList map { index =>
      registry.unpickle(reader.readArrayElem(pickle, index))
    }).asInstanceOf[::[T]]
  }
}

can be possible.

It will also be useful to write some docs about righting custom scalajs picklers (for noncase classes) as (at least for me) it is absolutely not clear how to write them. Some simple explanations with examples will be extremely useful

//for passing a list of Menu classes
  register[Menu]
  implicit object MenuConsPickler extends  GenericConsPickler[Menu]
  implicit object MenuConsUnpickler extends GenericConsUnpickler[Menu]
  register[::[Menu]]
sjrd commented 10 years ago

I agree that picklers for collections should be included by default.

However, note that you don't need all of this to be able to pickle Lists (of any type of elements). All you need to do is:

PicklerRegistry.register[::[Any]]
PicklerRegistry.register(Nil)
antonkulaga commented 10 years ago

I had to write them because I could not unpickle any complex classes that I received from Play and that contains lists =((( I received weird errors about "s property" =(( Here is my code that got json from play app ( https://github.com/denigma/semantic-web/blob/master/binding/src/main/scala/org/denigma/extensions/sq.scala in the end, get method), there I used JSON.parse because it did not work with request.response but worked with unpickle(JSON.parse(request.responseText))) Probably this procedure made demands to Lists tougher And here is my play code

    val testMenu: Menu = Menu(WebIRI("http://webintelligence.eu"),"Home", List(
      MenuItem(WebIRI("http://webintelligence.eu/pages/about"),"About"),
      MenuItem(WebIRI("http://webintelligence.eu/pages/project"),"Our projects")))

      RegisterPicklers.registerPicklers()

      val pickle: JsValue = PicklerRegistry.pickle(testMenu)
      Ok(pickle).as("application/json")

Until I wrote List support for Menus. And here are the menus themselves: https://github.com/denigma/semantic-web/blob/master/models/src/main/scala/models/Menus.scala

jlc commented 10 years ago

Hi,

It would indeed be very useful :)

As it was needed for our project, I have some initial support for Set and Map that have been backported in scala-js-pickling.

https://github.com/jlc/scala-js-pickling/commit/7dd0858216e7d4711fe5a6bdd971832a862a7761

@sjrd , would need your help to fix the registration for Option (None, Some), and List:

class BasePicklerRegistry extends PicklerRegistry { 
  ...
  private def registerBuiltinPicklers(): Unit = {
    ...
    register(None)
    register[Some[Any]]
    register[::[Any]] 
    register(Nil)
    ...
  }
}

An issue arises for Set() and Map() (empty), which require the ability to access scala.collection.immutable.Set.EmptySet and scala.collection.immutable.Map.EmptyMap, both private. It has been fixed thanks to:

registerInternal((Map[Nothing, Nothing]()).getClass, Pickler.MapPickler, Unpickler.MapUnpickler)
registerInternal((Set[Nothing]()).getClass, Pickler.SetPickler, Unpickler.SetUnpickler)

Would you please let me know what you thing, and if we can consider a pull request?

Post updates:

Enjoy your day! Cheers,

sjrd commented 6 years ago

Closing as I'm about to archive this repository.