Coder Social home page Coder Social logo

sjson's Introduction

sjson: Transparent JSON Serialization in Scala

sjson offers non intrusive serialization of Scala objects into JSON. You can use sjson to serialize built in types, the basic generic data types and any custom data type that you design. Two types of serialization are supported right now :-

  1. Reflection based that offers JSON serialization capabilities without any user intervention. You define your class, use some of the out-of-the-box annotations (if required) and invoke the serialization API
  2. Typeclass based, that defines a serialization protocol that needs to be implemented for custom data objects. For built-in types, the default protocol implementation comes out of the box. This is very much a work in progress and will evolve with time. The current implementation, however is fairly robust though not yet fully complete.

For more details of the implementation and sample examples, have a look at the wiki.

News

2011/09/01: sjson 0.15 released

  • fixed #37: Problem in typeclass based serialization using Seq
  • builds in Scala 2.9.1

2011/08/29: sjson 0.14 released

  • fixed a bug with serializing a combo of List, Map and Option
  • fixed #35: Need to distinguish between cases where we have a List of objects or a List of Maps
  • fixed #34: Bug in serializing structures where the OptionTypeHint is for a nested value
  • fixed #33: Bug in serializing composite structures like a List within a Map
  • fixed issue #32: Serializing case objects (singleton objects) using sjson
  • fixed #30: SJSON.toJSON() should handle primitive arrays
  • fixed issue #26: optionally remove empty objects & arrays from result
  • fixed #29 (#29)

2011/07/11: sjson 0.13 released

  • Bug fixes in reflection based API
  • Now compiles with scala 2.9.0-1
  • A few minor enhancements in typeclass based serialization

2011/05/16: sjson 0.12 released

  • Major improvements in reflection based API
  • De-serialization is more type-safe now – no need to cast
  • Improved deep serialization of generic structures in reflection based APIs
  • Improved test cases

2011/03/26: sjson 0.10 released

  • bug fixes in serialization of Enumerations and Options
  • builds with Scala 2.8.1 and Scala 2.9.0.RC1
  • refactoring of code
  • dependency on scalaz removed and moved to separate project sjson-scalaz

2010/09/16: sjson 0.8 released

  • type class based JSON serialization enhanced
  • fixed bug in reflection based serialization

2010/07/28: sjson 0.7 released

License

This software is licensed under the Apache 2 license, quoted below.

Licensed under the Apache License, Version 2.0 (the “License”); you may not
use this file except in compliance with the License. You may obtain a copy of
the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an “AS IS” BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations under
the License.

sjson's People

Contributors

akraievoy avatar debasishg avatar epabst avatar sadache avatar wspringer avatar xuwei-k avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sjson's Issues

Bug in serializing composite structures like a List within a Map

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.

How to serialize a List[SomeTrait]?

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.

Bug in serializing structures where the OptionTypeHint is for a nested value

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]])
}

2.11 release

We have a legacy dependency on this lib, can you please publish a scala 2.11 version?

Serialization from JSON fails

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).

Need to distinguish between cases where we have a List of objects or a List of Maps

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]])
}

Null handling in String values

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 ?

Cache for meta-data processing

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 ?

Strange JSON output

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"]

scala>

I guess the ObjectOutputStream that is used since 28.12 is adding the additional characters...

on deserialization Option[Long] is converted to Option[BigDecimal]

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)
        }
    }
}

Serialize None as []

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.

More control when serializing using BeanInfo

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:

  1. Introduce a new annotation, or extend one of the existing ones, to support custom serialization logic.
  2. Use reflection to determine whether an object provides a suitable 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

Upgrading Dispatch

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.

ignore missing fields while converting json to case class object

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.

scala 2.10 version?

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.

String ending with $ is not accepted

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

some helpers?

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.

Problem in typeclass based serialization using Seq

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.

Non-string map keys don't work

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.

custom error message for missing default constructor

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!

freemarker dependancy?

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>

Object references

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?

Reflection-based deserialization using Objenesis returns type AnyRef

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!

Serialization of java.util.List (JPA Entity)

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 ?

Reflection based serialization of not owned field types

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.

NPE during transformation

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 ...

Field#getGenericType instead of JSONTypeHint

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.

Serializing case objects (singleton objects) using sjson

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.

scala.MatchError when expecting a tuple but only null is given

"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.

SJSON.toJSON() should handle primitive arrays

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!

optionally remove empty objects & arrays from result

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.

Certain double values throw NumberFormatExceptions

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.