From 92cd1ffdcd1fd27c9f5b7405e6c57a1ded721670 Mon Sep 17 00:00:00 2001 From: shuang Date: Thu, 18 Feb 2021 17:28:18 +0800 Subject: [PATCH] feature/dynamic_resourceDoc: add typeNamePrefix when generate case class with JValue --- .../commons/util/JsonUtils.scala | 40 +++++++++--------- .../commons/util/JsonUtilsTest.scala | 41 +++++++++++++------ 2 files changed, 48 insertions(+), 33 deletions(-) diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/util/JsonUtils.scala b/obp-commons/src/main/scala/com/openbankproject/commons/util/JsonUtils.scala index bd0a05bac..38b4a3074 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/util/JsonUtils.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/util/JsonUtils.scala @@ -725,7 +725,7 @@ object JsonUtils { } } - private def getNestedJObjects(jObject: JObject): List[String] = { + private def getNestedJObjects(jObject: JObject, typeNamePrefix: String): List[String] = { val nestedObjects = collectField(jObject) { case (JField(_, _: JObject), _) => true case (JField(_, JArray((_: JObject) :: _)), _) => true @@ -741,18 +741,18 @@ object JsonUtils { val subTypes: List[String] = nestedObjects collect { case (JField(name, v: JObject), path) => - jObjectToCaseClass(v, name, getParentFiledName(path)) + jObjectToCaseClass(v, typeNamePrefix, name, getParentFiledName(path)) case (JField(name, JArray((v: JObject) :: _)), path) => - jObjectToCaseClass(v, name, getParentFiledName(path)) + jObjectToCaseClass(v, typeNamePrefix, name, getParentFiledName(path)) case (JField(name, JArray(JArray((v: JObject) :: _) :: _)), path) => - jObjectToCaseClass(v, name, getParentFiledName(path)) + jObjectToCaseClass(v, typeNamePrefix, name, getParentFiledName(path)) case (JField(name, JArray(JArray(JArray((v: JObject) :: _) :: _) :: _)), path) => - jObjectToCaseClass(v, name, getParentFiledName(path)) + jObjectToCaseClass(v, typeNamePrefix, name, getParentFiledName(path)) case (JField(name, JArray(JArray(JArray(JArray((v: JObject) :: _) :: _) :: _) :: _)), path) => - jObjectToCaseClass(v, name, getParentFiledName(path)) + jObjectToCaseClass(v, typeNamePrefix, name, getParentFiledName(path)) case (JField(name, JArray(JArray(JArray(JArray(JArray((v: JObject) :: _) :: _) :: _) :: _) :: _)), path) => - jObjectToCaseClass(v, name, getParentFiledName(path)) - case (JField(name, JArray(JArray(JArray(JArray(JArray(JArray(_ :: _) :: _) :: _) :: _) :: _) :: _)), path) => + jObjectToCaseClass(v, typeNamePrefix, name, getParentFiledName(path)) + case (JField(_, JArray(JArray(JArray(JArray(JArray(JArray(_ :: _) :: _) :: _) :: _) :: _) :: _)), path) => throw new IllegalArgumentException(s"Json field $path have too much nested level, max nested level be supported is 5.") } toList @@ -764,16 +764,16 @@ object JsonUtils { * @param jvalue * @return case class string */ - def toCaseClasses(jvalue: JValue): String = { + def toCaseClasses(jvalue: JValue, typeNamePrefix: String = ""): String = { validateJArray(jvalue) jvalue match { - case _: JBool => "type RootJsonClass = Boolean" - case _: JString => "type RootJsonClass = String" - case _: JDouble => "type RootJsonClass = Double" - case _: JInt => "type RootJsonClass = Long" + case _: JBool => s"type ${typeNamePrefix}RootJsonClass = Boolean" + case _: JString => s"type ${typeNamePrefix}RootJsonClass = String" + case _: JDouble => s"type ${typeNamePrefix}RootJsonClass = Double" + case _: JInt => s"type ${typeNamePrefix}RootJsonClass = Long" case jObject: JObject => validateJArray(jObject) - val allDefinitions = getNestedJObjects(jObject) :+ jObjectToCaseClass(jObject) + val allDefinitions = getNestedJObjects(jObject, typeNamePrefix) :+ jObjectToCaseClass(jObject, typeNamePrefix) allDefinitions mkString "\n" case jArray: JArray => @@ -785,9 +785,9 @@ object JsonUtils { case _: JDouble => "List[Double]" case _: JInt => "List[Long]" case v: JObject => - val itemsType = jObjectToCaseClass(v, "RootItem") + val itemsType = jObjectToCaseClass(v, typeNamePrefix, "RootItem") s"""$itemsType - |List[RootItemJsonClass] + |List[${typeNamePrefix}RootItemJsonClass] |""".stripMargin case v: JArray => val nestedItmType = buildArrayType(v) @@ -802,7 +802,7 @@ object JsonUtils { nestedItmType.replaceAll("(^|.*\\s+)(.+)\\s*$", "$1List[$2]") } // add type alias for last row - buildArrayType(jArray).replaceAll("(^|.*\\s+)(.+)\\s*$", "$1 type RootJsonClass = $2") + buildArrayType(jArray).replaceAll("(^|.*\\s+)(.+)\\s*$", s"$$1 type ${typeNamePrefix}RootJsonClass = $$2") case null | JNull | JNothing => throw new IllegalArgumentException(s"null value json can't generate case class") } @@ -810,7 +810,7 @@ object JsonUtils { } - private def jObjectToCaseClass(jObject: JObject, fieldName: String = "", parentFieldName: String = ""): String = { + private def jObjectToCaseClass(jObject: JObject, typeNamePrefix: String, fieldName: String = "", parentFieldName: String = ""): String = { val JObject(fields) = jObject val optionalFields = (jObject \ optionalFieldName) match { case JArray(arr) if arr.forall(_.isInstanceOf[JString]) => @@ -819,7 +819,7 @@ object JsonUtils { case _ => throw new IllegalArgumentException(s"Filed $optionalFieldName of $fieldName should be an array of String") } - def toCaseClassName(name: String) = s"${fieldName.capitalize}${name.capitalize}JsonClass" + def toCaseClassName(name: String) = s"$typeNamePrefix${fieldName.capitalize}${name.capitalize}JsonClass" val currentCaseClass: String = fields collect { case JField(name, v) if isBasicType(v) => @@ -850,7 +850,7 @@ object JsonUtils { val escapedFieldsName = reservedToEscaped.getOrElse(name, name) s"$escapedFieldsName: $fieldType" - } mkString(s"case class ${parentFieldName.capitalize}${if(fieldName.isEmpty) "Root" else fieldName.capitalize}JsonClass(", ", ", ")") + } mkString(s"case class $typeNamePrefix${parentFieldName.capitalize}${if(fieldName.isEmpty) "Root" else fieldName.capitalize}JsonClass(", ", ", ")") currentCaseClass } diff --git a/obp-commons/src/test/scala/com/openbankproject/commons/util/JsonUtilsTest.scala b/obp-commons/src/test/scala/com/openbankproject/commons/util/JsonUtilsTest.scala index 79b668639..68211ad8f 100644 --- a/obp-commons/src/test/scala/com/openbankproject/commons/util/JsonUtilsTest.scala +++ b/obp-commons/src/test/scala/com/openbankproject/commons/util/JsonUtilsTest.scala @@ -42,7 +42,7 @@ class JsonUtilsTest extends FlatSpec with Matchers { names should not contain ("nestField1") } - def toCaseClass(str: String): String = JsonUtils.toCaseClasses(json.parse(str)) + def toCaseClass(str: String, typeNamePrefix: String = ""): String = JsonUtils.toCaseClasses(json.parse(str), typeNamePrefix) "object json String" should "generate correct case class" taggedAs FunctionsTag in { @@ -66,15 +66,27 @@ class JsonUtilsTest extends FlatSpec with Matchers { |} |""".stripMargin } - val expectedCaseClass = - """case class AddressStreetJsonClass(road: String, number: Long) - |case class AddressJsonClass(name: String, code: Long, street: AddressStreetJsonClass) - |case class StreetJsonClass(name: String, width: Double) - |case class RootJsonClass(name: String, age: Option[java.lang.Long], isMarried: Boolean, weight: Option[java.lang.Double], `class`: String, `def`: Long, email: List[String], address: Option[List[AddressJsonClass]], street: StreetJsonClass)""".stripMargin + { + val expectedCaseClass = + """case class AddressStreetJsonClass(road: String, number: Long) + |case class AddressJsonClass(name: String, code: Long, street: AddressStreetJsonClass) + |case class StreetJsonClass(name: String, width: Double) + |case class RootJsonClass(name: String, age: Option[java.lang.Long], isMarried: Boolean, weight: Option[java.lang.Double], `class`: String, `def`: Long, email: List[String], address: Option[List[AddressJsonClass]], street: StreetJsonClass)""".stripMargin - val generatedCaseClass = toCaseClass(zson) + val generatedCaseClass = toCaseClass(zson) - generatedCaseClass should be (expectedCaseClass) + generatedCaseClass should be(expectedCaseClass) + } + {// test type name prefix + val expectedCaseClass = + """case class RequestAddressStreetJsonClass(road: String, number: Long) + |case class RequestAddressJsonClass(name: String, code: Long, street: RequestAddressStreetJsonClass) + |case class RequestStreetJsonClass(name: String, width: Double) + |case class RequestRootJsonClass(name: String, age: Option[java.lang.Long], isMarried: Boolean, weight: Option[java.lang.Double], `class`: String, `def`: Long, email: List[String], address: Option[List[RequestAddressJsonClass]], street: RequestStreetJsonClass)""".stripMargin + + val generatedCaseClass = toCaseClass(zson, "Request") + generatedCaseClass should be(expectedCaseClass) + } } "List json" should "generate correct case class" taggedAs FunctionsTag in { @@ -82,9 +94,8 @@ class JsonUtilsTest extends FlatSpec with Matchers { val listIntJson = """[1,2,3]""" val expectedCaseClass = """ type RootJsonClass = List[Long]""" - val generatedCaseClass = toCaseClass(listIntJson) - - generatedCaseClass should be(expectedCaseClass) + toCaseClass(listIntJson) should be(""" type RootJsonClass = List[Long]""") + toCaseClass(listIntJson, "Response") should be(""" type ResponseRootJsonClass = List[Long]""") } { val listObjectJson = @@ -101,11 +112,15 @@ class JsonUtilsTest extends FlatSpec with Matchers { val expectedCaseClass = """case class RootItemJsonClass(name: String, weight: Double) | type RootJsonClass = List[RootItemJsonClass]""".stripMargin - val generatedCaseClass = toCaseClass(listObjectJson) + val expectedRequestCaseClass = """case class RequestRootItemJsonClass(name: String, weight: Double) + | type RequestRootJsonClass = List[RequestRootItemJsonClass]""".stripMargin - generatedCaseClass should be(expectedCaseClass) + + toCaseClass(listObjectJson) should be(expectedCaseClass) + toCaseClass(listObjectJson, "Request") should be(expectedRequestCaseClass) } } + "List json have different type items" should "throw exception" taggedAs FunctionsTag in { val listJson = """["abc",2,3]"""