diff --git a/.gitignore b/.gitignore index 5a0e4a9..9b0346d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ .idea* +*.iws +*.ipr *.iml target - .classpath .project .settings .cache +/out/ diff --git a/build.sbt b/build.sbt index ab66de8..68e41a0 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -name := "jerkson" +name := "rickb777-jerkson" version := "0.7-SNAPSHOT" diff --git a/src/main/scala/com/codahale/jerkson/util/CaseClassSigParser.scala b/src/main/scala/com/codahale/jerkson/util/CaseClassSigParser.scala index f491abc..662046f 100644 --- a/src/main/scala/com/codahale/jerkson/util/CaseClassSigParser.scala +++ b/src/main/scala/com/codahale/jerkson/util/CaseClassSigParser.scala @@ -107,7 +107,7 @@ object CaseClassSigParser { val defaultMethod = try { Some(companionClass.getMethod("apply$default$%d".format(idx + 1))) } catch { - case _: Throwable ⇒ None // indicates no default value was supplied + case _: Exception ⇒ None // indicates no default value was supplied } val defaultValue = defaultMethod.map(m ⇒ Some(m.invoke(companionObject))).getOrElse(None) Tuple3(ms.name, typeRef2JavaType(t, factory, classLoader, containedTypes), defaultValue) :: Nil diff --git a/src/test/scala/com/codahale/jerkson/tests/CaseClassSupportSpec.scala b/src/test/scala/com/codahale/jerkson/tests/CaseClassSupportSpec.scala index 9c8ba17..10f8cbf 100644 --- a/src/test/scala/com/codahale/jerkson/tests/CaseClassSupportSpec.scala +++ b/src/test/scala/com/codahale/jerkson/tests/CaseClassSupportSpec.scala @@ -135,37 +135,131 @@ class CaseClassSupportSpec extends FlatSpec with ShouldMatchers { "any": true, "anyRef": "wah", "intMap": { - "1": "1" + "1": "10" }, "longMap": { - "2": 2 + "2": 20 } } """ - parse[CaseClassWithAllTypes](json) should equal( - CaseClassWithAllTypes( - map = Map("one" -> "two"), - set = Set(1, 2, 3), - string = "woo", - list = List(4, 5, 6), - seq = Seq(7, 8, 9), - indexedSeq = IndexedSeq(16, 17, 18), - vector = Vector(22, 23, 24), - bigDecimal = BigDecimal("12.0"), - bigInt = BigInt("13"), - int = 1, - long = 2L, - char = 'x', - bool = false, - short = 14, - byte = 15, - float = 34.5f, - double = 44.9d, - any = true, - anyRef = "wah", - intMap = Map(1 -> 1), - longMap = Map(2L -> 2L))) + val expected = CaseClassWithAllTypes( + map = Map("one" -> "two"), + set = Set(1, 2, 3), + string = "woo", + list = List(4, 5, 6), + seq = Seq(7, 8, 9), + indexedSeq = IndexedSeq(16, 17, 18), + vector = Vector(22, 23, 24), + bigDecimal = BigDecimal("12.0"), + bigInt = BigInt("13"), + int = 1, + long = 2L, + char = 'x', + bool = false, + short = 14, + byte = 15, + float = 34.5f, + double = 44.9d, + any = true, + anyRef = "wah", + intMap = Map(1 -> 10), + longMap = Map(2L -> 20L) + ) + val actual = parse[CaseClassWithAllTypes](json) + actual should equal(expected) + parse[CaseClassWithAllTypes](generate(actual)) should equal(expected) + } + + + "A case class with supplied optional members of Scala collection types" should "be parsable from a JSON object with those fields" in { + val json = """ + { + "map": { + "one": "two" + }, + "set": [1, 2, 3], + "list": [4, 5, 6], + "seq": [7, 8, 9], + "indexedSeq": [16, 17, 18], + "vector": [22, 23, 24], + "intMap": { + "1": 10 + }, + "longMap": { + "2": 20 + } + } + """ + + val expected = CaseClassWithOptionalCollectionTypes( + map = Some(Map("one" -> "two")), + set = Some(Set(1, 2, 3)), + list = Some(List(4, 5, 6)), + seq = Some(Seq(7, 8, 9)), + indexedSeq = Some(IndexedSeq(16, 17, 18)), + vector = Some(Vector(22, 23, 24)), + intMap = Some(Map(1 -> 10)), + longMap = Some(Map(2L -> 20L)) + ) + val actual = parse[CaseClassWithOptionalCollectionTypes](json) + actual should equal(expected) + val generatedJson = generate(actual).replaceAll("[\n\t ]", "") + generatedJson should equal(json.replaceAll("[\n\t ]", "")) + parse[CaseClassWithOptionalCollectionTypes](generatedJson) should equal(expected) + } + + + "A case class with optional members of empty Scala collection types" should "be parsable from a JSON object with those fields" in { + val json = """ + { + "map": {}, + "set": [], + "list": [], + "seq": [], + "collection": [], + "indexedSeq": [], + "randomAccessSeq": [], + "vector": [], + "intMap": {}, + "longMap": {} + } + """ + + val expected = CaseClassWithOptionalCollectionTypes( + map = Some(Map.empty), + set = Some(Set.empty), + list = Some(List.empty), + seq = Some(Seq.empty), + indexedSeq = Some(IndexedSeq.empty), + vector = Some(Vector.empty), + intMap = Some(Map.empty), + longMap = Some(Map.empty) + ) + val actual = parse[CaseClassWithOptionalCollectionTypes](json) + actual should equal(expected) + parse[CaseClassWithOptionalCollectionTypes](generate(actual)) should equal(expected) + } + + + "A case class with absent optional members of Scala collection types" should "be parsable from a JSON object with those fields" in { + val json = """ + {} + """ + + val expected = CaseClassWithOptionalCollectionTypes( + map = None, + set = None, + list = None, + seq = None, + indexedSeq = None, + vector = None, + intMap = None, + longMap = None + ) + val actual = parse[CaseClassWithOptionalCollectionTypes](json) + actual should equal(expected) + parse[CaseClassWithOptionalCollectionTypes](generate(actual)) should equal(expected) } "A case class nested inside of an object" should "be parsable from a JSON object" in { diff --git a/src/test/scala/com/codahale/jerkson/tests/ExampleCaseClasses.scala b/src/test/scala/com/codahale/jerkson/tests/ExampleCaseClasses.scala index 60117ec..cfd62bc 100644 --- a/src/test/scala/com/codahale/jerkson/tests/ExampleCaseClasses.scala +++ b/src/test/scala/com/codahale/jerkson/tests/ExampleCaseClasses.scala @@ -7,6 +7,7 @@ import com.codahale.jerkson.JsonSnakeCase case class CaseClass(id: Long, name: String) case class CaseClassWithDefaultString(id: Long, name: String = "Coda") + case class CaseClassWithDefaultInt(id: Long, answer: Int = 42) case class CaseClassWithLazyVal(id: Long) { @@ -59,6 +60,15 @@ case class CaseClassWithAllTypes(map: Map[String, String], intMap: Map[Int, Int], longMap: Map[Long, Long]) +case class CaseClassWithOptionalCollectionTypes(map: Option[Map[String, String]], + set: Option[Set[Int]], + list: Option[List[Int]], + seq: Option[Seq[Int]], + indexedSeq: Option[IndexedSeq[Int]], + vector: Option[Vector[Int]], + intMap: Option[Map[Int, Int]], + longMap: Option[Map[Long, Long]]) + object OuterObject { case class NestedCaseClass(id: Long)