99package org .locationtech .geomesa .features .kryo .json
1010
1111import com .esotericsoftware .kryo .io .{Input , Output }
12+ import com .fasterxml .jackson .databind .JsonNode
13+ import com .fasterxml .jackson .databind .node .{ArrayNode , ObjectNode }
1214import com .typesafe .scalalogging .LazyLogging
13- import org .json4s .JsonAST ._
14- import org .json4s .native .JsonMethods .{parse => _ }
1515import org .locationtech .geomesa .features .kryo .json .JsonPathParser ._
1616
1717import java .nio .charset .StandardCharsets
@@ -85,11 +85,9 @@ object KryoJsonSerialization extends LazyLogging {
8585 * @param json json string to serialize - must be a json object
8686 */
8787 def serialize (out : Output , json : String ): Unit = {
88- import org .json4s ._
89- import org .json4s .native .JsonMethods ._
9088 val obj = if (json == null ) { null } else {
9189 try {
92- parse (json)
90+ mapper.readTree (json)
9391 } catch {
9492 case NonFatal (e) =>
9593 logger.warn(s " Error parsing json: \n $json" , e)
@@ -105,11 +103,13 @@ object KryoJsonSerialization extends LazyLogging {
105103 * @param out output to write to
106104 * @param json object to serialize
107105 */
108- def serialize (out : Output , json : JValue ): Unit = {
109- json match {
110- case null | JNull => out.write(BooleanFalse )
111- case j : JObject => out.write(BooleanTrue ); writeDocument(out, j)
112- case j => out.write(NonDoc ); writeValue(out, " " , j)
106+ def serialize (out : Output , json : JsonNode ): Unit = {
107+ if (json == null || json.isNull) {
108+ out.write(BooleanFalse )
109+ } else if (json.isObject) {
110+ out.write(BooleanTrue ); writeDocument(out, json)
111+ } else {
112+ out.write(NonDoc ); writeValue(out, " " , json)
113113 }
114114 }
115115
@@ -122,12 +122,11 @@ object KryoJsonSerialization extends LazyLogging {
122122 * @return json as a string
123123 */
124124 def deserializeAndRender (in : Input ): String = {
125- import org .json4s .native .JsonMethods ._
126125 val json = deserialize(in)
127126 if (json == null ) {
128127 null
129128 } else {
130- compact(render( json) )
129+ mapper.writeValueAsString( json)
131130 }
132131 }
133132
@@ -139,7 +138,7 @@ object KryoJsonSerialization extends LazyLogging {
139138 * @param in input, pointing to the start of the json object
140139 * @return parsed json object
141140 */
142- def deserialize (in : Input ): JValue = {
141+ def deserialize (in : Input ): JsonNode = {
143142 try {
144143 in.readByte match {
145144 case BooleanFalse => null
@@ -176,19 +175,19 @@ object KryoJsonSerialization extends LazyLogging {
176175
177176 // primitive writing functions - in general will write a byte identifying the type, the key and then the value
178177
179- private def writeDocument (out : Output , name : String , value : JObject ): Unit = {
178+ private def writeDocument (out : Output , name : String , value : JsonNode ): Unit = {
180179 out.writeByte(DocByte )
181180 out.writeName(name)
182181 writeDocument(out, value)
183182 }
184183
185- // write a document without a name - used for the outer-most object which doesn't have a key
186- private def writeDocument (out : Output , value : JObject ): Unit = {
184+ // write a document without a name - used for the outermost object which doesn't have a key
185+ private def writeDocument (out : Output , value : JsonNode ): Unit = {
187186 val start = out.position()
188187 // write a placeholder that we will overwrite when we go back to write total length
189188 // note: don't just modify position, as that doesn't expand the buffer correctly
190189 out.writeInt(0 )
191- value.obj.foreach { case (name, elem) => writeValue(out, name, elem) }
190+ value.forEachEntry { case (name, elem) => writeValue(out, name, elem) }
192191 out.writeByte(TerminalByte ) // marks the end of our object
193192 // go back and write the total length
194193 val end = out.position()
@@ -197,74 +196,82 @@ object KryoJsonSerialization extends LazyLogging {
197196 out.setPosition(end)
198197 }
199198
200- private def writeValue (out : Output , name : String , value : JValue ): Unit = {
201- value match {
202- case v : JString => writeString(out, name, v)
203- case v : JObject => writeDocument(out, name, v)
204- case v : JArray => writeArray(out, name, v)
205- case v : JDouble => writeDouble(out, name, v)
206- case v : JInt => writeInt(out, name, v)
207- case v : JLong => writeLong(out, name, v)
208- case JNull => writeNull(out, name)
209- case v : JBool => writeBoolean(out, name, v)
210- case v : JDecimal => writeDecimal(out, name, v)
199+ private def writeValue (out : Output , name : String , value : JsonNode ): Unit = {
200+ if (value.isTextual || value.isBinary) {
201+ writeString(out, name, value.asText())
202+ } else if (value.isObject) {
203+ writeDocument(out, name, value)
204+ } else if (value.isArray) {
205+ writeArray(out, name, value)
206+ } else if (value.isDouble || value.isFloat) {
207+ writeDouble(out, name, value.asDouble())
208+ } else if (value.isInt || value.isShort) {
209+ writeInt(out, name, value.intValue())
210+ } else if (value.isLong) {
211+ writeLong(out, name, value.longValue())
212+ } else if (value.isNull) {
213+ writeNull(out, name)
214+ } else if (value.isBoolean) {
215+ writeBoolean(out, name, value.booleanValue())
216+ } else if (value.isBigDecimal) {
217+ writeDouble(out, name, value.asDouble())
218+ } else if (value.isBigInteger) {
219+ if (value.canConvertToInt) {
220+ writeInt(out, name, value.intValue())
221+ } else if (value.canConvertToLong) {
222+ writeLong(out, name, value.longValue())
223+ } else {
224+ logger.warn(s " Skipping int value that does not fit in a long: $value" )
225+ }
226+ } else {
227+ logger.warn(s " Unhandled JsonNode: $value" )
211228 }
212229 }
213230
214- private def writeArray (out : Output , name : String , value : JArray ): Unit = {
231+ private def writeArray (out : Output , name : String , value : JsonNode ): Unit = {
215232 out.writeByte(ArrayByte )
216233 out.writeName(name)
217234 // we store as an object where array index is the key
218- var i = - 1
219- val withKeys = value.arr.map { element => i += 1 ; (i.toString, element) } // note: side-effect in map
220- writeDocument(out, JObject (withKeys))
235+ var i = 0
236+ val obj = mapper.createObjectNode()
237+ while (i < value.size()) {
238+ obj.set(i.toString, value.get(i))
239+ i += 1
240+ }
241+ writeDocument(out, obj)
221242 }
222243
223- private def writeString (out : Output , name : String , value : JString ): Unit = {
244+ private def writeString (out : Output , name : String , value : String ): Unit = {
224245 out.writeByte(StringByte )
225246 out.writeName(name)
226- val bytes = value.values. getBytes(StandardCharsets .UTF_8 )
247+ val bytes = value.getBytes(StandardCharsets .UTF_8 )
227248 out.writeInt(bytes.length)
228249 out.write(bytes)
229250 out.writeByte(TerminalByte )
230251 }
231252
232- private def writeDecimal (out : Output , name : String , value : JDecimal ): Unit = {
253+ private def writeDouble (out : Output , name : String , value : Double ): Unit = {
233254 out.writeByte(DoubleByte )
234255 out.writeName(name)
235- out.writeDouble(value.values.toDouble )
256+ out.writeDouble(value)
236257 }
237258
238- private def writeDouble (out : Output , name : String , value : JDouble ): Unit = {
239- out.writeByte(DoubleByte )
259+ private def writeInt (out : Output , name : String , value : Int ): Unit = {
260+ out.writeByte(IntByte )
240261 out.writeName(name)
241- out.writeDouble (value.values )
262+ out.writeInt (value)
242263 }
243264
244- private def writeInt (out : Output , name : String , value : JInt ): Unit = {
245- if (value.values.isValidInt) {
246- out.writeByte(IntByte )
247- out.writeName(name)
248- out.writeInt(value.values.intValue)
249- } else if (value.values.isValidLong) {
250- out.writeByte(LongByte )
251- out.writeName(name)
252- out.writeLong(value.values.longValue)
253- } else {
254- logger.warn(s " Skipping int value that does not fit in a long: $value" )
255- }
256- }
257-
258- private def writeLong (out : Output , name : String , value : JLong ): Unit = {
265+ private def writeLong (out : Output , name : String , value : Long ): Unit = {
259266 out.writeByte(LongByte )
260267 out.writeName(name)
261- out.writeLong(value.values )
268+ out.writeLong(value)
262269 }
263270
264- private def writeBoolean (out : Output , name : String , v : JBool ): Unit = {
271+ private def writeBoolean (out : Output , name : String , value : Boolean ): Unit = {
265272 out.writeByte(BooleanByte )
266273 out.writeName(name)
267- out.writeByte(if (v.values ) BooleanTrue else BooleanFalse )
274+ out.writeByte(if (value ) BooleanTrue else BooleanFalse )
268275 }
269276
270277 private def writeNull (out : Output , name : String ): Unit = {
@@ -275,33 +282,39 @@ object KryoJsonSerialization extends LazyLogging {
275282 // primitive reading/skipping methods corresponding to the write methods above
276283 // assumes that the indicator byte and name have already been read
277284
278- private [json] def readDocument (in : Input ): JObject = {
285+ private [json] def readDocument (in : Input ): ObjectNode = {
279286 val end = in.position() + in.readInt() - 1 // last byte is the terminal byte
280- val elements = scala.collection.mutable. ArrayBuffer .empty[ JField ]
287+ val obj = mapper.createObjectNode()
281288 while (in.position() < end) {
282- elements.append(readValue(in))
289+ val (k, v) = readValue(in)
290+ obj.set(k, v)
283291 }
284292 in.skip(1 ) // skip over terminal byte
285- JObject (elements.toList)
293+ obj
286294 }
287295
288- private [json] def readValue (in : Input ): JField = {
296+ private [json] def readValue (in : Input ): ( String , JsonNode ) = {
289297 val switch = in.readByte()
290298 val name = in.readName()
291299 val value = switch match {
292- case StringByte => JString (readString(in))
300+ case StringByte => mapper.getNodeFactory.textNode (readString(in))
293301 case DocByte => readDocument(in)
294302 case ArrayByte => readArray(in)
295- case DoubleByte => JDouble (in.readDouble())
296- case IntByte => JInt (in.readInt())
297- case LongByte => JLong (in.readLong())
298- case NullByte => JNull
299- case BooleanByte => JBool (readBoolean(in))
303+ case DoubleByte => mapper.getNodeFactory.numberNode (in.readDouble())
304+ case IntByte => mapper.getNodeFactory.numberNode (in.readInt())
305+ case LongByte => mapper.getNodeFactory.numberNode (in.readLong())
306+ case NullByte => mapper.getNodeFactory.nullNode()
307+ case BooleanByte => mapper.getNodeFactory.booleanNode (readBoolean(in))
300308 }
301- JField (name, value)
309+ (name, value)
302310 }
303311
304- private [json] def readArray (in : Input ): JArray = JArray (readDocument(in).obj.map(_._2))
312+ private [json] def readArray (in : Input ): ArrayNode = {
313+ val obj = readDocument(in)
314+ val array = mapper.getNodeFactory.arrayNode(obj.size())
315+ obj.forEachEntry { case (_, v) => array.add(v) }
316+ array
317+ }
305318
306319 private [json] def skipDocument (in : Input ): Unit = in.skip(in.readInt - 4 ) // length includes bytes storing length
307320
0 commit comments