@@ -9,8 +9,6 @@ object jsonToCaseClass {
99 val (_, allCCs) = buildCC(j, " CC" , List .empty)
1010 val ccs =
1111 allCCs
12- // todo this is just a hack to get around duplicated nested objects
13- .distinctBy(_.name)
1412 .map(cc => cc.copy(content = cc.content.filter { case (key, value) => key.nonEmpty && value.nonEmpty }))
1513
1614 ccs.map(cc => (cc.name, renderCC(cc)))
@@ -19,52 +17,60 @@ object jsonToCaseClass {
1917 private def renderCC (cc : CC ): String =
2018 s " case class ${cc.name}( ${cc.content.map { case (key, value) => s " $key: $value" }.mkString(" , " )}) "
2119
22- private def buildCC (j : Json , nextLevelName : String , doneCCs : List [CC ]): (Option [ String ] , List [CC ]) = {
20+ private def buildCC (j : Json , nextLevelName : String , doneCCs : List [CC ]): (String , List [CC ]) = {
2321 j.fold(
24- Some (" Option[Any]" ) -> doneCCs,
25- _ => Some (" Boolean" ) -> doneCCs,
26- _ => Some (" Double" ) -> doneCCs,
27- _ => Some (" String" ) -> doneCCs,
28- array => {
29- val innerType = array.flatMap { ele =>
30- val (x, y) = buildCC(ele, nextLevelName, List .empty)
31- x.map(_ -> y)
32- }
33- innerType
34- .foldLeft[Option [(String , List [CC ])]](None )((left, right) =>
35- left.map { case (valueName, ccs) => (valueName, right._2 ++ ccs) }.orElse(Some (right)))
36- .map {
37- case (valueName, Nil ) => valueName -> doneCCs
38- case (valueName, ele :: Nil ) => valueName -> (ele :: doneCCs)
39- case (valueName, ele :: more) =>
40- val (nextLevelCCs, deeperCCs) = (ele :: more)
41- .partition(_.name == valueName)
22+ // todo decode not at all if null
23+ " Option[String]" -> doneCCs,
24+ _ => " Boolean" -> doneCCs,
25+ _ => " Double" -> doneCCs,
26+ _ => " String" -> doneCCs,
27+ array =>
28+ array.toList match {
29+ case all @ ele :: rest if all.forall(_.isObject) =>
30+ val innerType =
31+ rest.foldLeft(buildCC(ele, nextLevelName, doneCCs)) {
32+ case ((newValueName, aggCCs), nextJson) =>
33+ newValueName -> buildCC(nextJson, nextLevelName, aggCCs)._2
34+ }
35+
36+ val (valueName, ccs) = innerType match {
37+ case (valueName, Nil ) => valueName -> doneCCs
38+ case (valueName, ele :: Nil ) => valueName -> (ele :: Nil )
39+ case (valueName, ele :: more) =>
40+ val (nextLevelCCs, otherCCs) = (ele :: more)
41+ .partition(_.name.startsWith(valueName))
4242
43- val allContent = nextLevelCCs.map(_.content).fold(Map .empty)(_ ++ _)
44- val keyCountPerContent =
45- nextLevelCCs.map(cc => cc.content.map[String , Int ] { case (key, _) => (key, 1 ) }).combineAll
43+ val allContent = nextLevelCCs.map(_.content).fold(Map .empty)(_ ++ _)
44+ val keyCountPerContent =
45+ nextLevelCCs.map(cc => cc.content.map[String , Int ] { case (key, _) => (key, 1 ) }).combineAll
4646
47- val keyCount = keyCountPerContent .size
47+ val keyCount = nextLevelCCs .size
4848
49- val newCC = ele.copy(content = keyCountPerContent.map({
50- case (key, count) if count == keyCount => key -> allContent(key)
51- case (key, _) => key -> s " Option[ ${allContent(key)}] "
52- }))
49+ val newCC = ele.copy(content = keyCountPerContent.map({
50+ case (key, count) if count == keyCount => key -> allContent(key)
51+ case (key, _) => key -> s " Option[ ${allContent(key)}] "
52+ }))
53+ valueName -> (newCC :: otherCCs)
54+ }
5355
54- valueName -> (newCC :: deeperCCs ::: doneCCs)
55- }
56- .map { case (valueName, ccs) => Some (s " List[ $valueName] " ) -> ccs }
57- .getOrElse(Some (" List[String]" ) -> doneCCs)
56+ s " List[ $valueName] " -> ccs
57+ case ele :: rest if rest.forall(_ == ele) =>
58+ val (newValue, allCCs) = buildCC(ele, nextLevelName, doneCCs)
59+ s " List[ $newValue] " -> allCCs
60+ case _ => " List[String]" -> doneCCs
5861 },
5962 jObj => {
60- val (allNewCCs, newCC) = jObj.toMap.foldLeft(List .empty[ CC ] -> CC (nextLevelName, Map .empty)) {
61- case ((allCss , currCC), (key, value)) =>
62- val (newValue, allNewCCs) = buildCC(value, key, List .empty )
63- (allCss ++ allNewCCs,
64- newValue.map(newV => currCC.copy(content = currCC.content.updated(key, newV))).getOrElse(currCC ))
63+ val (allNewCCs, newCC) = jObj.toMap.foldLeft(doneCCs -> CC (nextLevelName, Map .empty)) {
64+ case ((allCCs , currCC), (key, value)) =>
65+ val safeNextLevelName = findFreeName(currCC :: allCCs, key )
66+ val (newValue, allNewCCs) = buildCC(value, safeNextLevelName, allCCs)
67+ (allNewCCs, currCC.copy(content = currCC.content.updated(key, newValue) ))
6568 }
66- (Some ( nextLevelName) , newCC :: allNewCCs)
69+ (nextLevelName, newCC :: allNewCCs)
6770 }
6871 )
6972 }
73+
74+ private def findFreeName (ccs : List [CC ], name : String ): String =
75+ if (ccs.exists(_.name == name)) findFreeName(ccs, name + " 1" ) else name
7076}
0 commit comments