debasishg / sjson Goto Github PK
View Code? Open in Web Editor NEWScala Json with capabilities for Scala Object Serialization
Home Page: http://debasishg.blogspot.com
Scala Json with capabilities for Scala Object Serialization
Home Page: http://debasishg.blogspot.com
Introspection of beans often lead to processing same meta-data repeatedly .. e.g. List of Beans lead to processing of the bean meta-data many times (O(n)). Can this be improved with a cache implementation ?
I don't know if this is fixable (I'm a Scala newbie and don't grasp the finer points of parametrized types), but I wanted to point out that using Objenesis for deserialization returns objects of type AnyRef
even when using something like:
object JJSON extends Serializer.SJSON with Objenesis { val classLoader = None }
case class Dog(name: String)
JJSON.in[Dog]("""{"name": "fido"}""")
Returns res0: AnyRef = Dog(fido)
rather than Dog = Dog(fido)
. This is not major by any means, but it would be nice not to have to call asInstanceOf[Dog]
on the return value.
Once again, I may be missing something important that makes this infeasible or impossible, but I wanted to point it out :)
Thanks for a great library!
Thanks for this great framework! One question comes to mind: AFAIK, standard JSON can't express object references. Do you plan to handle this use case and if yes, how?
I tried "sbt package" file and got....
C:\Users\tony\workspace\sjson>sbt package
C:\Users\tony\workspace\sjson>set SCRIPT_DIR=C:\sbt\
C:\Users\tony\workspace\sjson>java -Xmx512M -jar "C:\sbt\sbt-launch.jar" package
[warn] Credentials file C:\Users\tony.ivy2.credentials does not exist
[info] Building project sjson 0.8 against Scala 2.8.1
[info] using SJsonProject with sbt 0.7.5.RC0 and Scala 2.8.1
[info]
[info] == template ==
[info] Running fmpp.tools.CommandLine -U all -S C:\Users\tony\workspace\sjson\src\m
c\main\scala\sjson\json\Serializer.scala C:\Users\tony\workspace\sjson\src\main\sca
workspace\sjson\src\main\scala\sjson\json\Util.scala C:\Users\tony\workspace\sjson
\Users\tony\workspace\sjson\src\main\scala\sjson\json\Protocol.scala C:\Users\tony
json\Generic.scala
java.lang.ClassNotFoundException: fmpp.tools.CommandLine
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at sbt.Run.getMainMethod(Run.scala:74)
at sbt.Run.run0(Run.scala:59)
at sbt.Run.execute$1(Run.scala:48)
at sbt.Run$$anonfun$run$2.apply(Run.scala:51)
at sbt.Run$$anonfun$run$2.apply(Run.scala:51)
at sbt.TrapExit$.executeMain$1(TrapExit.scala:33)
at sbt.TrapExit$$anon$1.run(TrapExit.scala:42)
[info] == template ==
[error] Error running template: Nonzero exit code: 1
[info]
[info] Total time: 0 s, completed 14/01/2011 2:18:19 PM
[info]
[info] Total session time: 1 s, completed 14/01/2011 2:18:19 PM
[error] Error during build.
C:\Users\tony\workspace\sjson>
I think it would be a great idea to have the option of removing any 'unnecessary' elements from the JSON output. By that I mean empty objects like parent: {}
and empty arrays like children: []
.
I'm aware that this may cause problems if the according field is not properly initialized by a default constructor. That's why I'd make this an optional functionality.
What are the results? Shorter, lighter JSON results that can be transmitted faster and save space when being persisted.
When I deserialize an object that has a Option[Long] field (or [int]) the resulting object suddenly has a Option[BigDecimal] field - even when I specify the correct @OptionTypeHint!
Is this a bug or did I do something wrong?
Example:
import org.specs2.mutable.Specification
import reflect.BeanInfo
import sjson.json._
import annotation.target._
@BeanInfo
case class Person(name: String,
@(OptionTypeHint@field)(value = classOf[Long]) age: Option[Long]) {
private def this() = this ("", None)
}
class Test extends Specification {
"SJSON" should {
"deserialize Option[Long] fields" >> {
// initialize
val age = Some(12L)
val p = new Person("Daniel", age)
// serialize and deserialize
val json = Serializer.SJSON.out(p)
val obj = Serializer.SJSON.in[Person](json).asInstanceOf[Person]
// check result
obj.age match {
case b: Option[BigDecimal] => // THROWN
throw new RuntimeException("deserialization resulted in Option[BigDecimal]")
case l: Option[Long] => println("works")
}
obj.age must beEqualTo(age)
}
}
}
When dispatch got rebooted, its json lib got removed. So what would be the ideal upgrade path for json library behind sjson?
Looks like Dispatch Reboot supports json4s (native & jackson) and lift-json out of the box. And apparently json4s(native) is pretty much lift-json only without the problems of lift release cycle.
Should be able to serialize classes of the form ..
@BeanInfo
case class Security[T <: SecurityType](name: String, securityType: T) {
def this() = this("", null.asInstanceOf[T])
}
sealed trait SecurityType
case object STOCK extends SecurityType
case object FI extends SecurityType
case object MUTUAL_FUND extends SecurityType
case object GOVT_BOND extends SecurityType
@BeanInfo
case class BondTrade(
instrument: Security[FI.type],
@(JSONProperty @getter)(ignoreIfNull = true, ignore = false) @(OptionTypeHint@field)(value = classOf[scala.collection.Map[_, _]]) taxFees: Option[Map[String, BigDecimal]] = None,
account: String) {
def this() = this(null, None, "")
}
Note use of case objects for which there's no standard JSON notation.
How to differentiate between "null" and null while Serializer.in ?
case class Foo(str: String)
val f = Foo(null)
Serializer.out(f) => JSON value : "null"
During Serializer.in[Foo] => how do I know if the value was "null" string or the value null ?
Introspector.getBeanInfo(clazz).getPropertyDescriptors is returning empty for nested classes.
We have a legacy dependency on this lib, can you please publish a scala 2.11 version?
There is this project called 'Salat' here on Github that is able to serialize case classes without any 'help' from annotations.
Have a look: https://github.com/novus/salat/wiki/Design
Maybe this mechanism could be build into sjson?
Why not to use
val field = context.get.getDeclaredField(props.get(name).get)
val fieldInnerType = field.getGenericType.asInstanceOf[ParameterizedType].getActualTypeArguments()(0)
instead of
val field = context.get.getDeclaredField(props.get(name).get)
val ann = field.getAnnotation(classOf[JSONTypeHint])
when determining types of elements in list field?
For example here https://github.com/debasishg/sjson/blob/master/src/main/scala/sjson/json/JsBean.scala#L182
Thanks,
Oleg.
I recently forgot to define a default constructor (when using reflection) and had a hard time discovering what I did wrong. The error message was "next on empty iterator" coming from:
def newInstance[T](clazz: Class[T])(op: T => Unit): T = {
val constructor =
clazz.getDeclaredConstructors.filter(_.getParameterTypes.length == 0).head
Maybe you could turn it into something like:
def newInstance[T](clazz: Class[T])(op: T => Unit): T = {
val constructor =
clazz.getDeclaredConstructors.filter(_.getParameterTypes.length == 0)
.headOption.getOrElse(sys.error("no default constructor found on " + clazz))
This way it would be much easier to find the reason for the exception!
Cheers!
Hi,
while testing a Jersey JSON MessageBodyWriter I noticed a strange JSON serialization like this:
-------------------- mvn scala:console output --------------------
scala> import sjson.json.Serializer.SJSON
import sjson.json.Serializer.SJSON
import sjson.json.Serializer.SJSON
scala> new String(SJSON.out(List("a","b")))
new String(SJSON.out(List("a","b")))
res2: java.lang.String =
��w
["a", "b"]
I guess the ObjectOutputStream that is used since 28.12 is adding the additional characters...
with 0.8.0 SJSON.out(someBeanWithOptionField) doesn't write the field if it's None
this means that after SJSON.in the field will have it's default value, and not None
I think None should be serialized as an empty array or null to allow for deserialization
@Test
def getOption() {
import sjson.json.Serializer.SJSON
import sjson.json.OptionTypeHint
assertEquals(SampleConfigOption(None), SJSON.in[SampleConfigOption](SJSON.out(SampleConfigOption(None))))
}
@BeanInfo case class SampleConfigOption(@(OptionTypeHint@field)(classOf[String]) //this seems redundant
user: Option[String]) {
def this() = this (Some("default"))
}
Thanks,
Oleg.
Hello.
I'd like to use reflection based serialization but my objects have fields of type java.util.UUID.
I can't add @BeanInfo annotation and modify this type because it's a library type.
I'm able to define Format for class UUID to serialize uuid.toString and deserialize UUID.fromString() but how to use it in reflection based serializer?
I think that JsBean methods: fromJSON and toJSON should take into account some implicit formats that may be defined.
Hi I have a case class .
case class User(
name: Name,
gender: String ,age:string}
This is a sample case class in some cases my json is incomplete like
{"name":"sagar","gendar":"male"}
Now when I am trying to convert this json to case class using following code
import sjson.json._
val js = JsValue.fromString(json);
val userObj = fromjsonUser
It's giving me error . Is there any way we can create case class objects from incomplete JSON.
In CollectionTypes.mapFormat the reads and writes functions look like:
{{{
implicit def mapFormat[K, V](implicit fmtk: Format[K], fmtv: Format[V]) : Format[Map[K, V]] = new Format[Map[K, V]] {
def writes(ts: Map[K, V]) = JsObject(ts.map{case (k, v) => ((tojson(k.toString)).asInstanceOf[JsString], tojson(v)(fmtv))})
def reads(json: JsValue) = json match {
case JsObject(m) => Map() ++ m.map{case (k, v) => (fromjsonK(fmtk), fromjsonV(fmtv))}
case _ => throw new RuntimeException("Map expected")
}
}
}}}
The writes is always assuming that the key is a string, doing "k.toString" before passing it to tojson. This is causing problems if you have a class (even a simple wrapper class around string) that is used as the key for the map.
"net.debasishg" % "sjson_2.9.2" % "0.19"
scalaVersion := "2.9.3"
test code:
package test
case class QueryJson(
time_from: Int,
time_to: (Int, Int)
)
object Main {
import sjson.json._
import DefaultProtocol._
import dispatch.classic.json.JsonParser
import scala.util.parsing.input.CharSequenceReader
implicit val QueryJsonFormat: Format[QueryJson] = asProduct2("time_from", "time_to")(QueryJson)(QueryJson.unapply(_).get)
def main(args: Array[String]) {
val q = QueryJson(0, (0, 1))
println(JsonSerialization.tojson(q))
val js = JsonSerialization.fromjson[QueryJson](JsonParser(new CharSequenceReader("{\"time_from\":0,\"time_to\":null}")))
println(js.time_from)
println(js.time_to)
}
}
sbt run result:
scala.MatchError: null (of class dispatch.classic.json.JsNull$)
at sjson.json.BasicTypes$$anon$3.reads(StandardTypes.scala:27)
at sjson.json.BasicTypes$$anon$3.reads(StandardTypes.scala:23)
at sjson.json.JsonSerialization$.fromjson(JsonSerialization.scala:9)
at sjson.json.Generic$$anon$4.reads(Generic.scala:64)
at sjson.json.JsonSerialization$.fromjson(JsonSerialization.scala:9)
at test.Main$.main(Main.scala:21)
at test.Main.main(Main.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
I think thowing a RuntimeException
will be better, like what List and Seq do.
Currently Date is not handled in JSON. Need to incorporate.
With this code
@BeanInfo case class Config(user: User) {
def this() = this (new User)
}
@BeanInfo case class User(email: String, pass: String) {
def this() = this ("", "")
}
and this json:
{"user":{
"email":"[email protected]",
"pass":"4884$"
}}
i get
java.lang.RuntimeException: Cannot make object for :4884$
at scala.sys.package$.error(package.scala:27)
at sjson.json.JsBean$$anonfun$1.apply(JsBean.scala:313)
sjson_2.9.1-0.15
Hi there --
First of all, I'd like to extend my gratitude to all contributors for providing this really useful library.
In addition, I wanted to know whether it'd be possible to offer users more control when serializing a type that's been annotated with BeanInfo. Specifically, it'd be very helpful to provide a way to tell the serializer that one or more properties ought to be handled through custom logic.
For example:
@scala.reflect.BeanInfo
case class Response (content: String, status: Int, uri: java.net.URI)
val r = Response("turtles", 42, new java.net.URI("http://example.org"))
val j = new String(sjson.json.Serializer.SJSON.out(r))
The default behavior as I understand it is to recursively serialize each field in a uniform manner. In the case of uri
(of type java.net.URI
) the result will be a JSON object containing various properties like host, port, path and so on. This behavior is useful and makes sense in the majority of cases.
However, in a couple of specific places, I need to override it. For example, I'd like the URI to serialize as a JSON string instead of an object. The logic to do this is trivial (e.g. calling either toString
or toASCIIString
), yet as far as I can tell from looking at JsBean.scala
, there is no way to specify it.
It looks like the options I have are to either (a) switch to JsValues
; (b) switch to one of the type class-based approaches; or (c) use only primitive types for fields instead of more appropriate complex types.
For me, option (a) is not adequate, because it defeats the purpose altogether. Furthermore, option (b) seems too heavyweight when the current approach works so well in most cases with no intervention. Thus I've stuck with (c) so far. Perhaps I'm missing another way to do what I want?
Otherwise, the following two ideas come to mind:
toJSON
method or equivalent, and if so, invoke it during serialization instead of the default bean property handler.(Note that the two aren't mutually exclusive. In fact, the annotation could be used to guide or disable the method invocation.)
If there is interest in something like this, I could work on a patch to provided the functionality, though I should mention that I'm new to Scala, so it may take a few tries :).
Thanks once again!
Regards,
Alvaro
Is there any support planned for persisting scala Enumeration values?
I'm just trying out sjson while doing a simple exercise. I really dig the typeclass based approach. But I got stuck on something like this:
trait SubUnit
case class Dept(name: String, manager: Employee, subUnits: List[SubUnit]) extends SubUnit
case class Employee(name: String, salary: Double) extends SubUnit
Serializing Employee works like this (imports eluded):
implicit val EmployeeFormat: Format[Employee] = asProduct2("name", "salary")(Employee)(Employee.unapply(_).get)
but I'm stuck on Dept, apparently because of the List[SubUnit] type parameter - I can't provide a typeclass instance of that trait. How should I approach this. I get the feeling that I'm missing something really obvoius here.
Since both Map and a Scala object are stored as Maps within JsObject, we need to process the following case differently from the case where we have a List of objects. fromJSON needs to take care of this.
@BeanInfo
case class ListOfMap(
@(JSONTypeHint@field)(value = classOf[Shop]) shops: List[Map[String, Shop]]) {
def this() = this(List.empty[Map[String, Shop]])
}
Hi! I use Scala 2.9.0.RC3, sjson_2.9.0.RC3 v0.11 and my following test fails:
import sjson.json.JSONTypeHint
import reflect.BeanInfo
import org.scalatest.FlatSpec
import org.scalatest.matchers.ShouldMatchers
import sjson.json.Serializer.SJSON
class SjsonTest extends FlatSpec with ShouldMatchers {
@BeanInfo case class StoredQuery(id: String,@JSONTypeHint(classOf[Parameter]) param: Parameter)
@BeanInfo case class Parameter(name: String)
val storedQuery = new StoredQuery("queryId",
new Parameter("param")
)
"A stored query" should "be serialized into JSON and back" in {
val actualJSON = SJSON.out(storedQuery)
println(new String(actualJSON))
val actualQuery = SJSON.in[StoredQuery](actualJSON)
actualQuery should be === storedQuery
}
}
SJSON.in[StoredQuery](actualJSON)
fails with next on empty iterator
exception. Unfortunately, I don't have complete stacktrace (ide issue).
Currently:
scala> sjson.json.Serializer.SJSON.toJSON(Map("data" -> Array[java.lang.Integer](0)))
res2: String = {"data":[0]}
scala> sjson.json.Serializer.SJSON.toJSON(Map("data" -> Array(0)))
java.lang.UnsupportedOperationException: Class class [I not supported for conversion
It would be convenient if SJSON could handle these primitive arrays as well. Thanks!
JSON parser makes BigDecimal out of all JSON numbers. De-serialization process needs to take care of this and make appropriate conversions.
Hi there ..
am facing a NPE and actually have no idea how to fix it.
My environment:
Scala: 2.8.1
sjson: 2.8.1_0.8
The exception:
java.lang.NullPointerException
at sjson.json.JsBean$$anonfun$3.apply(JsBean.scala:287)
at sjson.json.JsBean$$anonfun$3.apply(JsBean.scala:285)
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:35)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:206)
at scala.collection.mutable.ArrayOps.map(ArrayOps.scala:35)
at sjson.json.JsBean$class.toJSON(JsBean.scala:285)
at sjson.json.Serializer$SJSON$.toJSON(Serializer.scala:112)
at sjson.json.Serializer$SJSON$class.out(Serializer.scala:38)
at sjson.json.Serializer$SJSON$.out(Serializer.scala:112)
at de.liventy.xfunds.ws.ResourcesUtil$class.serializeAsJSON(ProfileResource.scala:27)
at de.liventy.xfunds.ws.ShopResource.serializeAsJSON(ShopResource.scala:21)
The underlying classes:
trait ResourcesUtil {
def serializeAsJSON(obj: AnyRef): String = new String(Serializer.SJSON.out(obj))
def deserializeJSON[T](json: Array[Byte])(implicit m: Manifest[T]): AnyRef =
Serializer.SJSON.inT(m)
}
@JsonIgnoreProperties(Array("navigationcategory.sushiBarSourceCategoryId"))
class NavigationCategory {
@JsonProperty("navigationcategory.hasSubCategory") var hasSubCategory: Boolean = _
@JsonProperty("navigationcategory.navigationCategoryId") var id: Long = _
@JsonProperty("navigationcategory.overNavigationCategoryId") var overId: Long = _
@JsonProperty("navigationcategory.navigationCategoryNavisionId") var navisionId: Long = _
@JsonProperty("navigationcategory.navigationCategoryName") var name: String = _
@JsonProperty("navigationcategory.totalNumberOfProducts") var totalNumberOfProducts: Long = _
var resources:List[NavigationCategoryResource] = _
def setHasSubCategory(b:String){
hasSubCategory= if (b.equals("true")){true} else {false}
}
def setResources(jl:java.util.List[NavigationCategoryResource]){
resources = jl.toList
}
}
class NavigationCategoryResource{
@JsonProperty("resource.fileUrl") var fileUrl: String = _
@JsonProperty("resource.link") var link: String = _
@JsonProperty("resource.logicalCode") var logicalCode: String = _
}
Any hint or help is appreciated ...
Wouldnt it be nice to have a oblect some implicits for the writes method
to reduce the ammount of code to write?
Such that
def writes(p: Person): JsValue ={
import WriteUtil._
JsObject(("lastName",p.lastName),...)
}
instead of
JsObject(List((tojson("lastName").asInstanceOf[JsString], tojson(p.lastName)), ...))
So you get the option to reduce the ammount of code.
Hi Debasish,
first of thank you for your nice tool and your quick response to my last question.
I am actually running into a StackOverflowError using:
sjson 2.8.1
scala 2.8.1
jackson 1.8.0
Im currently running a JPA / Scala application having the following two entities:
@BeanInfo
@entity
case class Profile {
...
@OneToMany(cascade = Array(CascadeType.ALL), fetch = FetchType.EAGER)
@BeanProperty
var pools:java.util.List[Pool] = _
...
}
@BeanInfo
@entity
class Pool {
...
@BeanProperty
@manytoone
var profile:Profile = _
}
As long as Profile.pools List is empty, the json serialization works properly
Once it is populated, the application is producing a StackOverflowException:
13.05.2011 16:16:00 com.sun.jersey.spi.container.ContainerResponse mapMappableContainerException
SCHWERWIEGEND: The exception contained within MappableContainerException could not be mapped to a response, re-throwing to the HTTP container
java.lang.StackOverflowError
at scala.reflect.ClassManifest$class.newArray(ClassManifest.scala:97)
at scala.reflect.ClassManifest$ClassTypeManifest.newArray(ClassManifest.scala:197)
at scala.collection.mutable.ArrayBuilder$ofRef.mkArray(ArrayBuilder.scala:51)
at scala.collection.mutable.ArrayBuilder$ofRef.resize(ArrayBuilder.scala:57)
at scala.collection.mutable.ArrayBuilder$ofRef.ensureSize(ArrayBuilder.scala:69)
at scala.collection.mutable.ArrayBuilder$ofRef.$plus$eq(ArrayBuilder.scala:74)
at scala.collection.mutable.ArrayBuilder$ofRef.$plus$eq(ArrayBuilder.scala:44)
at scala.collection.TraversableLike$$anonfun$filter$1.apply(TraversableLike.scala:240)
at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:34)
at scala.collection.mutable.ArrayOps.foreach(ArrayOps.scala:35)
at scala.collection.TraversableLike$class.filter(TraversableLike.scala:239)
at scala.collection.mutable.ArrayOps.filter(ArrayOps.scala:35)
at sjson.json.JsBean$class.toJSON(JsBean.scala:277)
at sjson.json.Serializer$SJSON$.toJSON(Serializer.scala:112)
at sjson.json.JsBean$$anonfun$5.apply(JsBean.scala:304)
at sjson.json.JsBean$$anonfun$5.apply(JsBean.scala:285)
at scala.collection.TraversableLike$WithFilter$$anonfun$map$2.apply(TraversableLike.scala:786)
at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:34)
at scala.collection.mutable.ArrayOps.foreach(ArrayOps.scala:35)
at scala.collection.TraversableLike$WithFilter.map(TraversableLike.scala:785)
at sjson.json.JsBean$class.toJSON(JsBean.scala:285)
at sjson.json.Serializer$SJSON$.toJSON(Serializer.scala:112)
at sjson.json.JsBean$$anonfun$5.apply(JsBean.scala:304)
at sjson.json.JsBean$$anonfun$5.apply(JsBean.scala:285)
at scala.collection.TraversableLike$WithFilter$$anonfun$map$2.apply(TraversableLike.scala:786)
at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:34)
at scala.collection.mutable.ArrayOps.foreach(ArrayOps.scala:35)
at scala.collection.TraversableLike$WithFilter.map(TraversableLike.scala:785)
at sjson.json.JsBean$class.toJSON(JsBean.scala:285)
at sjson.json.Serializer$SJSON$.toJSON(Serializer.scala:112)
at sjson.json.JsBean$$anonfun$5.apply(JsBean.scala:304)
at sjson.json.JsBean$$anonfun$5.apply(JsBean.scala:285)
The snipplet that serializes any object:
def serializeAsJSON(obj: AnyRef): String = new String(Serializer.SJSON.out(obj))
The snipplet that produces the StackOverflow
serializeAsJSON(pool)
The problem looks obvious to me. Instead of using a Scala List, I have to use the Java list to be JPA compliant.
Any hint or any idea how to solve this problem ?
Consider the following class where the OptionTypeHint refers to a class which is not the field itself, but a structure which is embedded within the field. In the following case classOf[String] refers to the value of the Map - Option[String], not the field securityTypes itself.
@BeanInfo
case class MapOfOptionalString(
@(OptionTypeHint@field)(value = classOf[String]) securityTypes: Map[String, Option[String]]) {
def this() = this(Map.empty[String, Option[String]])
}
Tuple2 is getting de-serialized but only at the top level. Need to recurse down.
Currently all Scala classes need a visible default constructor for de-serialization. The constructor need not be public, but has to be visible, maybe package private. Can we make this private ?
Suppose we have a class like ..
@BeanInfo
case class MapOfListOfString(securityTypes: Map[String, List[String]]) {
def this() = this(Map.empty[String, List[String]])
}
In the de-serialization the contents of the list are not properly de-serialized. e.g. for a List[String], we will have JsString as elements of the list.
Any plans to provide a version for scala 2.10? I'm using sjson in a project I would like to upgrade to 2.10.
from: Jeff Crilly [email protected]
I have some of the typeclass serialization working, but am running into a problem w/ a case class that contains a Seq field...
I'm trying to pattern this after the examples at https://github.com/debasishg/sjson/blob/master/src/test/scala/sjson/json/Protocols.scala
Here's what I've got, but its not compiling...
// the following is scalaxb generated...
case class User(val id : scala.Option[scala.Predef.String],
val username : scala.Predef.String,
val org : scala.Predef.String, val firstname : scala.Predef.String, val lastname : scala.Predef.String
// other fields removed for brevity
) extends java.lang.Object with scala.ScalaObject with scala.Product { ... }
// The following is not generated, and is a wrapper for the User list...
case class DataGridResult (totalCount: String, success: Boolean, results: Seq[User])
// Update! if use a List[User] instead of Seq[User] then it works.
// and the "Protocol" adapter...
object DataGridResultProtocol extends DefaultProtocol {
import dispatch.json._
import JsonSerialization._
implicit object UserFormat extends Format[User] {
def reads(json: JsValue): User = json match {
case JsObject(m) =>
User(
fromjsonOption[String],
fromjsonString,
fromjsonString,
fromjsonString
// other fields removed for brevity
)
case _ => throw new RuntimeException("JsObject expected")
}
def writes(p: User): JsValue =
JsObject(List(
(tojson("id").asInstanceOf[JsString], tojson(p.id.getOrElse(""))),
(tojson("username").asInstanceOf[JsString], tojson(p.username)),
(tojson("firstname").asInstanceOf[JsString], tojson(p.firstname)),
(tojson("lastname").asInstanceOf[JsString], tojson(p.lastname))
// other fields to be added
))
}
implicit val DataGridFormat: Format[DataGridResult] =
asProduct3("totalCount", "success", "results")(DataGridResult)(DataGridResult.unapply(_).get) // <== there is obviously something wrong with this.
}
Any idea on who how to get the Seq[User] type to work? Do i need to use viaSeq()? (if so, a pointer would be helpful.)
Update: after i drafted this note, I changed the "results" to a List[User] instead of a Seq[User]... this works for classes that I control, but if the generated classes have Seq[] it will be a problem.
Double.PositiveInfinity, Double.NaN, etc.
In my local branch I've got:
implicit object DoubleFormat extends Format[Double] {
def writes(o: Double) = try {
JsValue.apply(o)
}
catch {
// we need Infinity/NaN goodness
case e: NumberFormatException => JsValue.apply(o.toString)
}
def reads(json: JsValue) = json match {
case JsString(n) => n.toDouble
case JsNumber(n) => n.doubleValue
case _ => throw new RuntimeException("Double (or string) expected")
}
}
I'm not 100% sure the wisdom of this, but it works for me.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.