scouchdb icon indicating copy to clipboard operation
scouchdb copied to clipboard

Suggestions for persisting a set/list of class objects?

Open jpc001 opened this issue 13 years ago • 1 comments

Hi Debasish

Firstly, I'd like to thank you for sharing scouchdb and sjson, they make working with Scala and CouchDB much easier!

I'm trying to use scouchdb (cloned from github a few days ago along with sjson 0.7 using Scala 2.8.0 final) to persist objects that contain a list of classes. The basic idea is that I want to represent something like a 'folder' that is only allowed to contain certain types of objects. For example, I may want one folder to contain only JPG, PNG or TIFF files, but another folder to contain only PDF files. Each of the file types is defined as a different class, so I create subclasses of my generic 'folder', e.g. ImageFolder (which sets the acceptable classes to JPG, PNG and TIFF) and PdfFolder (which sets the acceptable classes to PDF). This makes it easy to test if someone is adding an acceptable object to a folder. I hope this is clear!

However, trying to persist an object with a list of class objects results in an error:

java.lang.UnsupportedOperationException: Class class $Proxy3 not supported for conversion

I can sort of work around this by changing the code to use canonical class names (i.e. List[String]), but then I'm starting to change my core classes to suite the persistence model, which is less than ideal. It also means I need to manage the marshalling of the classes into class names and vice-versa when unmarshalling.

Here some simplified code that illustrates the issue:

import java.lang.Class import scala.reflect._ import scala.annotation.target._ import scouch.db._ import dispatch._ import dispatch.json._ import dispatch.json.JsHttp._ import sjson.json._

class SampleScouchdbClass(@BeanProperty val name: String) {

@BeanProperty
@(JSONTypeHint @field)(value = classOf[Class[_]])
val classes: List[Class[_ <: SampleScouchdbClass]] = List(classOf[SampleScouchdbClass])

}

object SampleScouchdbClass {

def main(args: Array[String]): Unit = {

        val http = new Http
    val sampleDb = Db(Couch(), "rms")

    var sample = new SampleScouchdbClass("Sample 1")

    val doc = Doc(sampleDb, sample.name)
    http(doc add sample)
}

}

The full error stack is:

Exception in thread "main" java.lang.UnsupportedOperationException: Class class $Proxy3 not supported for conversion at sjson.json.JsBean$class.toJSON(JsBean.scala:256) at sjson.json.JsBean$.toJSON(JsBean.scala:311) at sjson.json.JsBean$$anonfun$toJSON$2.apply(JsBean.scala:234) at sjson.json.JsBean$$anonfun$toJSON$2.apply(JsBean.scala:234) at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:206) at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:206) at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:34) at scala.collection.mutable.ArrayOps.foreach(ArrayOps.scala:34) at scala.collection.TraversableLike$class.map(TraversableLike.scala:206) at scala.collection.mutable.ArrayOps.map(ArrayOps.scala:34) at sjson.json.JsBean$class.toJSON(JsBean.scala:234) at sjson.json.JsBean$.toJSON(JsBean.scala:311) at sjson.json.JsBean$$anonfun$5.apply(JsBean.scala:280) at sjson.json.JsBean$$anonfun$5.apply(JsBean.scala:261) at scala.collection.TraversableLike$WithFilter$$anonfun$map$2.apply(TraversableLike.scala:787) at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:34) at scala.collection.mutable.ArrayOps.foreach(ArrayOps.scala:34) at scala.collection.TraversableLike$WithFilter.map(TraversableLike.scala:786) at sjson.json.JsBean$class.toJSON(JsBean.scala:261) at sjson.json.JsBean$.toJSON(JsBean.scala:311) at sjson.json.JsBean$$anonfun$toJSON$1.apply(JsBean.scala:231) at sjson.json.JsBean$$anonfun$toJSON$1.apply(JsBean.scala:231) at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:206) at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:206) at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:61) at scala.collection.immutable.List.foreach(List.scala:45) at scala.collection.TraversableLike$class.map(TraversableLike.scala:206) at scala.collection.immutable.List.map(List.scala:45) at sjson.json.JsBean$class.toJSON(JsBean.scala:231) at sjson.json.JsBean$.toJSON(JsBean.scala:311) at sjson.json.JsBean$$anonfun$5.apply(JsBean.scala:280) at sjson.json.JsBean$$anonfun$5.apply(JsBean.scala:261) at scala.collection.TraversableLike$WithFilter$$anonfun$map$2.apply(TraversableLike.scala:787) at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:34) at scala.collection.mutable.ArrayOps.foreach(ArrayOps.scala:34) at scala.collection.TraversableLike$WithFilter.map(TraversableLike.scala:786) at sjson.json.JsBean$class.toJSON(JsBean.scala:261) at sjson.json.JsBean$.toJSON(JsBean.scala:311) at scouch.db.Doc.add(Database.scala:263) at com.x.persistence.SampleScouchdbClass$.main(SampleScouchdbClass.scala:31) at com.x.persistence.SampleScouchdbClass.main(SampleScouchdbClass.scala)

Any suggestions/ideas on how to approach this problem would be much appreciated! I'm new to Scala and CouchDb, so my apologies in advance if I'm doing this in an unusual way.

Regards Ben

jpc001 avatar Sep 17 '10 13:09 jpc001

I will look into the problem ASAP. But on first look, my hunch is that JSON serialization of Class objects is failing. I am not sure if Class[] is JSON serializable at all or not. I think for the time being you need to use List[String] with the class names till I come up with a better suggestion.

Very soon I will be updating scouchdb with type class serialization that I introduced into sjson recently. Then I think I would be able to suggest u a better alternative. For the time being, please bear with the List[String] based solution :) ..

Thanks for using scouchdb & sjson.

debasishg avatar Sep 17 '10 14:09 debasishg