-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathGsonToGalliaData.scala
112 lines (89 loc) · 5.48 KB
/
GsonToGalliaData.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package gallia
package data
package json
import aptus._
import aptus.aptjson.GsonParser
// ===========================================================================
object GsonToGalliaData {
def parseRecursively(c: Cls, jsonString: String): Obj =
jsonString
.pipe(GsonParsing.parseObject)
.pipe(GsonToGalliaData.convertRecursively(c))
// ---------------------------------------------------------------------------
def convertRecursively(c: Cls)(o: Obj): Obj =
c .fields
.flatMap { field =>
c.unknownKeys(o).assert(_.isEmpty) // necessary for union types (see 220615165554)
o .attemptKey(field.key)
.map { value =>
field.key ->
processField(field.info)(value) } }
.pipe(gallia.obj)
// ===========================================================================
def parseGsonJsonElement(info: meta.InfoLike)(value: String): AnyValue =
parseJsonString(info.isNesting, info.subInfo1.multiple)(value)
.pipe(processField(info))
// ===========================================================================
private def processField(info: meta.InfoLike)(value: AnyValue): AnyValue =
info.valueExtractionWithFailures {
// ---------------------------------------------------------------------------
nestedGalliaClass => multiple =>
if (!multiple) value.asInstanceOf[ Obj ].pipe(convertRecursively(nestedGalliaClass))
else value.asInstanceOf[Seq[Obj ]].map (convertRecursively(nestedGalliaClass)) } {
// ---------------------------------------------------------------------------
bsc => multiple =>
if (!multiple) value .pipe(_basicValue(bsc))
else value.asInstanceOf[Seq[_]].toList.map (_basicValue(bsc)) }
// ===========================================================================
private def _basicValue(basicType: BasicType)(value: AnyValue): AnyValue =
basicType match {
case BasicType._String => value.asInstanceOf[String]
case BasicType._Boolean => value.asInstanceOf[Boolean]
case BasicType._Double => value.asInstanceOf[Double]
case BasicType._Int => BasicType._Int.parseAnyToDouble(value)
// ---------------------------------------------------------------------------
case _: BasicType._Enm => BasicType._Enm.parseStringAsAny(value)
// ---------------------------------------------------------------------------
case BasicType._Long => BasicType._Long .parseAnyToDouble(value)
case BasicType._Float => BasicType._Float.parseAnyToDouble(value)
case BasicType._Byte => BasicType._Byte .parseAnyToDouble(value)
case BasicType._Short => BasicType._Short.parseAnyToDouble(value)
// ---------------------------------------------------------------------------
case BasicType._BigInt => stringOrLong (BigInt .apply, BigInt .apply)(value)
case BasicType._BigDec => stringOrDouble(BigDecimal.apply, BigDecimal.apply)(value)
// ---------------------------------------------------------------------------
case BasicType._LocalDate => stringOrLong(BasicType._LocalDate .pair)(value)
case BasicType._LocalDateTime => stringOrLong(BasicType._LocalDateTime.pair)(value)
case BasicType._Instant => stringOrLong(BasicType._Instant .pair)(value)
// ---------------------------------------------------------------------------
case BasicType. _LocalTime => BasicType._LocalTime .parseStringAsAny(value)
case BasicType._OffsetDateTime => BasicType._OffsetDateTime.parseStringAsAny(value)
case BasicType. _ZonedDateTime => BasicType._ZonedDateTime .parseStringAsAny(value)
// ---------------------------------------------------------------------------
case BasicType._Binary => BasicType._Binary.parseStringAsAny(value)
}
// ===========================================================================
private[json] def stringOrLong[T](pair: (String => T, Long => T)): Any => T = stringOrLong(pair._1, pair._2)
private[json] def stringOrLong[T](ifString: String => T, ifLong: Long => T) : Any => T =
_ match {
case s: String => ifString(s)
case n: Number => ifLong (numberToLong(n)) }
// ---------------------------------------------------------------------------
private[json] def stringOrDouble[T](ifString: String => T, ifDouble: Double => T): Any => T =
_ match {
case s: String => ifString(s)
case n: Number => ifDouble(n.doubleValue) }
// ===========================================================================
private[json] def numberToLong(n: Number): Long =
n .doubleValue
.assert(gallia.reflect.BasicTypeUtils.doubleFitsLong)
.pipe(d => d.toLong.assert(_.toDouble == d))
// ===========================================================================
private def parseJsonString(nesting: Boolean, multiple: Boolean)(value: JsonString): AnyValue =
(nesting, multiple) match { // spilling for instance does not support union types
case (false, false) => GsonParser.stringToPrimitiveValueAny (value) /* Vle */
case (false, true ) => GsonParser.stringToPrimitiveValueAnys(value) /* Seq[Vle] */
case (true , false) => GsonToObj .fromObjectString (value) /* Obj */
case (true , true ) => GsonToObj .fromArrayString (value) /* Seq[Obj] */ }
}
// ===========================================================================