Skip to content

Commit

Permalink
Merge pull request #52 from xuwei-k/case-class
Browse files Browse the repository at this point in the history
add boilerplate methods for case class Format
  • Loading branch information
eed3si9n committed Jun 21, 2017
2 parents fdeda72 + 1b4cec1 commit a7628e6
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 0 deletions.
82 changes: 82 additions & 0 deletions core/src/main/boilerplate/sjsonnew/CaseClassFormats.scala.template
@@ -0,0 +1,82 @@
/*
* Original implementation (C) 2009-2011 Debasish Ghosh
* Adapted and extended in 2011 by Mathias Doenitz
* Adapted and extended in 2016 by Eugene Yokota
*
* 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.
*/

package sjsonnew

trait CaseClassFormats {

// simple alias for reduced verbosity
private[this] type JF[A] = JsonFormat[A]
private[this] type K[A] = JsonKeyWriter[A]


[2..22#def caseClass[[#K1: K#], [#A1: JF#], Z](applyFunc: ([#A1#]) => Z, unapplyFunc: Z => Option[([#A1#])])([#key1: K1#]): JF[Z] =
caseClass1[[#K1#], [#A1#], Z](applyFunc, unapplyFunc)([#key1#])

def caseClass1[[#K1#], [#A1#], Z](applyFunc: ([#A1#]) => Z, unapplyFunc: Z => Option[([#A1#])])([#key1: K1#])(implicit [#A1: JF[A1]#], [#K1: K[K1]#]): JF[Z] = new JsonFormat[Z] {
def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): Z = jsOpt match {
case Some(js) =>
unbuilder.beginObject(js)
val z = applyFunc(
[#unbuilder.readField[A1](K1.write(key1))#]
)
unbuilder.endObject()
z
case None =>
deserializationError("Expected JsObject but found None")
}

def write[J](obj: Z, builder: Builder[J]): Unit = {
val t = unapplyFunc(obj).get
builder.beginObject()
[#builder.addField(K1.write(key1), t._1)#
]
builder.endObject()
}
}

def caseClassArray1[[#A1#], Z](applyFunc: ([#A1#]) => Z, unapplyFunc: Z => Option[([#A1#])])(implicit [#A1: JF[A1]#]): JF[Z] = {
new JsonFormat[Z] {
def write[J](t: Z, builder: Builder[J]): Unit = {
val x = unapplyFunc(t).get
builder.beginArray()
[#A1.write(x._1, builder)#
]
builder.endArray()
}

def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): Z =
jsOpt match {
case Some(js) =>
unbuilder.beginArray(js)
[#val a1 = unbuilder.nextElement#
]
val xs = applyFunc([#A1.read(Some(a1), unbuilder)#])
unbuilder.endArray()
xs
case None =>
applyFunc([#A1.read(None, unbuilder)#])
}
}
}

def caseClassArray[[#A1: JF#], Z](applyFunc: ([#A1#]) => Z, unapplyFunc: Z => Option[([#A1#])]): JF[Z] =
caseClassArray1[[#A1#], Z](applyFunc, unapplyFunc)
#
]
}
1 change: 1 addition & 0 deletions core/src/main/scala/sjsonnew/BasicJsonProtocol.scala
Expand Up @@ -34,5 +34,6 @@ trait BasicJsonProtocol
with JavaExtraFormats
with CalendarFormats
with ImplicitHashWriters
with CaseClassFormats

object BasicJsonProtocol extends BasicJsonProtocol
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2011 Mathias Doenitz
* Adapted and extended in 2016 by Eugene Yokota
*
* 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.
*/

package sjsonnew
package support.spray

import spray.json.{JsonFormat => _, _}
import org.specs2.mutable._

class CaseClassFormatsSpec extends Specification with BasicJsonProtocol {

private case class Foo(a: Int, b: String)
private val foo = Foo(42, "bar")

"case class Json Object Format" should {
implicit val instance: JsonFormat[Foo] =
BasicJsonProtocol.caseClass(Foo.apply _, Foo.unapply _)("a", "b")

val json = JsObject("a" -> JsNumber(42), "b" -> JsString("bar"))

"convert to a JsObject" in {
Converter.toJsonUnsafe(foo) mustEqual json
}
"be able to convert a JsObject to a case class" in {
Converter.fromJsonUnsafe[Foo](json) mustEqual foo
}
}

"case class Json Array Format" should {
implicit val instance: JsonFormat[Foo] =
BasicJsonProtocol.caseClassArray(Foo.apply _, Foo.unapply _)

val json = JsArray(JsNumber(42), JsString("bar"))

"convert to a JsArray" in {
Converter.toJsonUnsafe(foo) mustEqual json
}
"be able to convert a JsArray to a case class" in {
Converter.fromJsonUnsafe[Foo](json) mustEqual foo
}
}

}

0 comments on commit a7628e6

Please sign in to comment.