Created
October 2, 2013 17:29
-
-
Save Narigo/6797285 to your computer and use it in GitHub Desktop.
Making json API typesafe... Is this a good idea?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/main/scala/org/vertx/scala/core/json/Json.scala b/src/main/scala/org/vertx/scala/core/json/Json.scala | |
index d756a32..b6d32d5 100644 | |
--- a/src/main/scala/org/vertx/scala/core/json/Json.scala | |
+++ b/src/main/scala/org/vertx/scala/core/json/Json.scala | |
@@ -17,51 +17,6 @@ | |
import scala.annotation.implicitNotFound | |
-@implicitNotFound(msg = "Cannot find add operations for type ${T}") | |
-trait JsonElemOps[T] { | |
- def addToObj(o: JsonObject, key: String, v: T): JsonObject | |
- def addToArr(a: JsonArray, v: T): JsonArray | |
-} | |
- | |
-object JsonElemOps { | |
- implicit object JsonStringElem extends JsonElemOps[String] { | |
- def addToObj(o: JsonObject, key: String, v: String): JsonObject = o.putString(key, v) | |
- def addToArr(a: JsonArray, v: String): JsonArray = a.addString(v) | |
- } | |
- implicit object JsonIntElem extends JsonElemOps[Int] { | |
- def addToObj(o: JsonObject, key: String, v: Int): JsonObject = o.putNumber(key, v) | |
- def addToArr(a: JsonArray, v: Int): JsonArray = a.addNumber(v) | |
- } | |
- implicit object JsonBoolElem extends JsonElemOps[Boolean] { | |
- def addToObj(o: JsonObject, key: String, v: Boolean): JsonObject = o.putBoolean(key, v) | |
- def addToArr(a: JsonArray, v: Boolean): JsonArray = a.addBoolean(v) | |
- } | |
- implicit object JsonFloatElem extends JsonElemOps[Float] { | |
- def addToObj(o: JsonObject, key: String, v: Float): JsonObject = o.putNumber(key, v) | |
- def addToArr(a: JsonArray, v: Float): JsonArray = a.addNumber(v) | |
- } | |
- implicit object JsonJsObjectElem extends JsonElemOps[JsonObject] { | |
- def addToObj(o: JsonObject, key: String, v: JsonObject): JsonObject = o.putObject(key, v) | |
- def addToArr(a: JsonArray, v: JsonObject): JsonArray = a.addObject(v) | |
- } | |
- implicit object JsonJsArrayElem extends JsonElemOps[JsonArray] { | |
- def addToObj(o: JsonObject, key: String, v: JsonArray): JsonObject = o.putArray(key, v) | |
- def addToArr(a: JsonArray, v: JsonArray): JsonArray = a.addArray(v) | |
- } | |
- implicit object JsonJsElem extends JsonElemOps[JsonElement] { | |
- def addToObj(o: JsonObject, key: String, v: JsonElement): JsonObject = o.putElement(key, v) | |
- def addToArr(a: JsonArray, v: JsonElement): JsonArray = a.addElement(v) | |
- } | |
- implicit object JsonBinaryElem extends JsonElemOps[Array[Byte]] { | |
- def addToObj(o: JsonObject, key: String, v: Array[Byte]): JsonObject = o.putBinary(key, v) | |
- def addToArr(a: JsonArray, v: Array[Byte]): JsonArray = a.addBinary(v) | |
- } | |
- implicit object JsonAnyElem extends JsonElemOps[Any] { | |
- def addToObj(o: JsonObject, key: String, v: Any): JsonObject = o.putValue(key, v) | |
- def addToArr(a: JsonArray, v: Any): JsonArray = a.add(v) | |
- } | |
-} | |
- | |
/** | |
* Helper to construct JsonObjects and JsonArrays. | |
* | |
@@ -76,7 +31,7 @@ | |
* @param fields The fieldName -> value pairs | |
* @return A JsonObject containing the name -> value pairs. | |
*/ | |
- def apply(fields: (String, Any)*): JsonObject = obj(fields: _*) | |
+ def apply(fields: (String, JsonElemOps[_])*): JsonObject = obj(fields: _*) | |
/** | |
* Creates a JsonArray from a sequence of values. | |
@@ -84,7 +39,7 @@ | |
* @param elements The elements to put into the JsonArray. | |
* @return A JsonArray containing the provided elements. | |
*/ | |
- def apply(elements: Seq[Any]): JsonArray = arr(elements) | |
+ def apply(elements: JsonElemOps[_]*): JsonArray = arr(elements: _*) | |
/** | |
* Creates a JsonArray from an encoded JSON string. | |
@@ -121,9 +76,9 @@ | |
* @param fields The fieldName -> value pairs | |
* @return A JsonObject containing the name -> value pairs. | |
*/ | |
- def obj(fields: (String, Any)*): JsonObject = { | |
+ def obj(fields: (String, JsonElemOps[_])*): JsonObject = { | |
val o = new JsonObject() | |
- fields.foreach(f => addToObject(o, f._1, f._2)) | |
+ fields.foreach(f => f._2.addToObj(o, f._1)) | |
o | |
} | |
@@ -133,18 +88,11 @@ | |
* @param elements The elements to put into the JsonArray. | |
* @return A JsonArray containing the provided elements. | |
*/ | |
- def arr(fields: Seq[Any]): JsonArray = { | |
+ def arr(fields: JsonElemOps[_]*): JsonArray = { | |
val a = new JsonArray() | |
- fields.foreach(f => addToArray(a, f)) | |
+ fields.foreach(f => f.addToArr(a)) | |
a | |
} | |
- private def addToArray[T: JsonElemOps](a: JsonArray, fieldValue: T) = { | |
- implicitly[JsonElemOps[T]].addToArr(a, fieldValue) | |
- } | |
- | |
- private def addToObject[T: JsonElemOps](o: JsonObject, fieldName: String, fieldValue: T) = { | |
- implicitly[JsonElemOps[T]].addToObj(o, fieldName, fieldValue) | |
- } | |
- | |
+ def listToArray(fields: Seq[JsonElemOps[_]]): JsonArray = arr(fields: _*) | |
} | |
\ No newline at end of file | |
diff --git a/src/main/scala/org/vertx/scala/core/json/package.scala b/src/main/scala/org/vertx/scala/core/json/package.scala | |
index 865db88..0cacdb9 100644 | |
--- a/src/main/scala/org/vertx/scala/core/json/package.scala | |
+++ b/src/main/scala/org/vertx/scala/core/json/package.scala | |
@@ -16,6 +16,7 @@ | |
package org.vertx.scala.core | |
import scala.collection.mutable.Map | |
+import scala.annotation.implicitNotFound | |
/** | |
* @author swilliams | |
@@ -37,4 +38,56 @@ | |
def asMap: Map[String, AnyRef] = internal.toMap.asScala | |
} | |
+ @implicitNotFound(msg = "Cannot find add operations for type ${T}") | |
+ trait JsonElemOps[T] { | |
+ def addToObj(o: JsonObject, key: String): JsonObject | |
+ def addToArr(a: JsonArray): JsonArray | |
+ val data: T | |
+ } | |
+ | |
+ implicit class JsonStringElem(val data: String) extends JsonElemOps[String] { | |
+ def addToObj(o: JsonObject, key: String): JsonObject = o.putString(key, data) | |
+ def addToArr(a: JsonArray): JsonArray = a.addString(data) | |
+ } | |
+ implicit class JsonIntElem(val data: Int) extends JsonElemOps[Int] { | |
+ def addToObj(o: JsonObject, key: String): JsonObject = o.putNumber(key, data) | |
+ def addToArr(a: JsonArray): JsonArray = a.addNumber(data) | |
+ } | |
+ implicit class JsonBoolElem(val data: Boolean) extends JsonElemOps[Boolean] { | |
+ def addToObj(o: JsonObject, key: String): JsonObject = o.putBoolean(key, data) | |
+ def addToArr(a: JsonArray): JsonArray = a.addBoolean(data) | |
+ } | |
+ implicit class JsonDoubleElem(val data: Double) extends JsonElemOps[Double] { | |
+ def addToObj(o: JsonObject, key: String): JsonObject = o.putNumber(key, data) | |
+ def addToArr(a: JsonArray): JsonArray = a.addNumber(data) | |
+ } | |
+ implicit class JsonLongElem(val data: Long) extends JsonElemOps[Long] { | |
+ def addToObj(o: JsonObject, key: String): JsonObject = o.putNumber(key, data) | |
+ def addToArr(a: JsonArray): JsonArray = a.addNumber(data) | |
+ } | |
+ implicit class JsonFloatElem(val data: Float) extends JsonElemOps[Float] { | |
+ def addToObj(o: JsonObject, key: String): JsonObject = o.putNumber(key, data) | |
+ def addToArr(a: JsonArray): JsonArray = a.addNumber(data) | |
+ } | |
+ implicit class JsonJsObjectElem(val data: JsonObject) extends JsonElemOps[JsonObject] { | |
+ def addToObj(o: JsonObject, key: String): JsonObject = o.putObject(key, data) | |
+ def addToArr(a: JsonArray): JsonArray = a.addObject(data) | |
+ } | |
+ implicit class JsonJsArrayElem(val data: JsonArray) extends JsonElemOps[JsonArray] { | |
+ def addToObj(o: JsonObject, key: String): JsonObject = o.putArray(key, data) | |
+ def addToArr(a: JsonArray): JsonArray = a.addArray(data) | |
+ } | |
+ implicit class JsonJsElem(val data: JsonElement) extends JsonElemOps[JsonElement] { | |
+ def addToObj(o: JsonObject, key: String): JsonObject = o.putElement(key, data) | |
+ def addToArr(a: JsonArray): JsonArray = a.addElement(data) | |
+ } | |
+ implicit class JsonBinaryElem(val data: Array[Byte]) extends JsonElemOps[Array[Byte]] { | |
+ def addToObj(o: JsonObject, key: String): JsonObject = o.putBinary(key, data) | |
+ def addToArr(a: JsonArray): JsonArray = a.addBinary(data) | |
+ } | |
+ // implicit object JsonAnyElem extends JsonElemOps[Any] { | |
+ // def addToObj(o: JsonObject, key: String, v: Any): JsonObject = o.putValue(key, v) | |
+ // def addToArr(a: JsonArray, v: Any): JsonArray = a.add(v) | |
+ // } | |
+ | |
} | |
\ No newline at end of file | |
diff --git a/src/test/scala/org/vertx/scala/tests/core/eventbus/EventBusTest.scala b/src/test/scala/org/vertx/scala/tests/core/eventbus/EventBusTest.scala | |
index 37a12c8..89109f1 100644 | |
--- a/src/test/scala/org/vertx/scala/tests/core/eventbus/EventBusTest.scala | |
+++ b/src/test/scala/org/vertx/scala/tests/core/eventbus/EventBusTest.scala | |
@@ -4,7 +4,7 @@ | |
import org.vertx.scala.testtools.TestVerticle | |
import org.vertx.testtools.VertxAssert._ | |
import org.vertx.scala.core.eventbus.Message | |
-import org.vertx.scala.core.json.Json | |
+import org.vertx.scala.core.json._ | |
import java.util.concurrent.CountDownLatch | |
import java.util.concurrent.atomic.AtomicInteger | |
import org.vertx.scala.core.json.JsonObject | |
diff --git a/src/test/scala/org/vertx/scala/tests/core/json/JsonTest.scala b/src/test/scala/org/vertx/scala/tests/core/json/JsonTest.scala | |
index 55a6619..1255455 100644 | |
--- a/src/test/scala/org/vertx/scala/tests/core/json/JsonTest.scala | |
+++ b/src/test/scala/org/vertx/scala/tests/core/json/JsonTest.scala | |
@@ -34,15 +34,13 @@ | |
"foo" -> "foo text", | |
"bar" -> 3.45d, | |
"baz" -> false, | |
- "myInt" -> Integer.MAX_VALUE | |
- ) | |
+ "myInt" -> Integer.MAX_VALUE) | |
assertEquals("foo text", obj.getString("foo")) | |
assertEquals(3.45d, obj.getValue[Double]("bar"), 1e-15) | |
assertEquals(false, obj.getBoolean("baz")) | |
assertEquals(Integer.MAX_VALUE, obj.getInteger("myInt")) | |
assertEquals(enc, obj.encode()) | |
- | |
} | |
@@ -55,7 +53,7 @@ | |
val scalaMapFields: scala.collection.Map[String, AnyRef] = wrapped.asMap | |
//Get the original object | |
- val obj2:JsonObject = wrapped | |
+ val obj2: JsonObject = wrapped | |
assertEquals("foo text", scalaMapFields("foo")) | |
assertEquals(true, obj2.getBoolean("optional")) | |
@@ -66,85 +64,66 @@ | |
def jsonArrayTest() { | |
val enc = """["f",3,"b",7,35.4,true]""" | |
- val array = Json.arr(List("f", 3, "b", 7, 35.4f, true)) | |
+ val array = Json.arr("f", 3, "b", 7, 35.4f, true) | |
assertEquals(6, array.size()) | |
assertEquals(enc, array.encode()) | |
} | |
- | |
@Test | |
- def customObjTest(){ | |
+ def customObjTest() { | |
import java.util.Date | |
- case class Custom(date:Date, other:Boolean) | |
+ case class Custom(date: Date, other: Boolean) | |
+ implicit class customObj(val data: Custom) extends JsonElemOps[Custom] { | |
+ def addToArr(a: JsonArray): JsonArray = a.add(data) | |
+ def addToObj(o: JsonObject, key: String): JsonObject = o.putValue(key, data) | |
+ } | |
+ | |
val info = Custom(new Date(), false) | |
- val obj1 = Json.obj("custom" -> info) | |
+ val obj1 = Json.obj("custom" -> info) | |
assertEquals(info, obj1.getValue[Custom]("custom")) | |
} | |
@Test | |
- def nestedObjectsTest(){ | |
+ def nestedObjectsTest() { | |
val obj = | |
Json.obj( | |
- "webappconf" -> Json.obj( | |
- "port" -> 8080, | |
- "ssl" -> false, | |
- "bridge" -> true, | |
- "inbound_permitted" -> Json.arr( | |
- Seq(Json.obj( | |
- "address" -> "acme.bar", | |
- "match" -> Json.obj( | |
- "action" -> "foo" | |
- )), | |
- Json.obj( | |
- "address" -> "acme.baz", | |
- "match" -> Json.obj( | |
- "action" -> "index" | |
- )) | |
- ) | |
- ), | |
- "outbound_permitted" -> Json.arr( | |
- Seq(new JsonObject()) | |
- ) | |
- ) | |
- ) | |
+ "webappconf" -> Json.obj( | |
+ "port" -> 8080, | |
+ "ssl" -> false, | |
+ "bridge" -> true, | |
+ "inbound_permitted" -> Json.arr( | |
+ Json.obj( | |
+ "address" -> "acme.bar", | |
+ "match" -> Json.obj("action" -> "foo")), | |
+ Json.obj( | |
+ "address" -> "acme.baz", | |
+ "match" -> Json.obj("action" -> "index"))), | |
+ "outbound_permitted" -> Json.arr(new JsonObject()))) | |
assertEquals(jsonString, obj.encode()) | |
} | |
- | |
@Test | |
- def nestedObjectsShorterVersionTest(){ | |
- val obj = | |
- Json( | |
- "webappconf" -> Json( | |
- "port" -> 8080, | |
- "ssl" -> false, | |
- "bridge" -> true, | |
- "inbound_permitted" -> Json( | |
- Seq(Json( | |
- "address" -> "acme.bar", | |
- "match" -> Json( | |
- "action" -> "foo" | |
- )), | |
- Json( | |
- "address" -> "acme.baz", | |
- "match" -> Json( | |
- "action" -> "index" | |
- )) | |
- ) | |
- ), | |
- "outbound_permitted" -> Json( | |
- Seq(new JsonObject()) | |
- ) | |
- ) | |
- ) | |
+ def nestedObjectsShorterVersionTest() { | |
+ val obj = Json.obj( | |
+ "webappconf" -> Json.obj( | |
+ "port" -> 8080, | |
+ "ssl" -> false, | |
+ "bridge" -> true, | |
+ "inbound_permitted" -> Json( | |
+ Json.obj( | |
+ "address" -> "acme.bar", | |
+ "match" -> Json.obj("action" -> "foo")), | |
+ Json.obj( | |
+ "address" -> "acme.baz", | |
+ "match" -> Json.obj("action" -> "index")))), | |
+ "outbound_permitted" -> Json(Json.obj())) | |
assertEquals(jsonString, obj.encode()) | |
} | |
- | |
private def jsonString = { | |
""" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment