All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.datasonnet.spi.ujsonUtils.scala Maven / Gradle / Ivy

package com.datasonnet.spi

/*-
 * Copyright 2019-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import ujson._

import scala.jdk.CollectionConverters.{MapHasAsJava, SeqHasAsJava}
import scala.util.control.TailCalls.{TailRec, done, tailcall}

object ujsonUtils {
  def strValueOf(str: String): Str = Str(str)

  def stringValueOf(value: ujson.Value): String = String.valueOf(value.value)

  def parse(jsonData: String): Value = ujson.read(ujson.Readable.fromString(jsonData))

  def read(s: Readable, trace: Boolean = false): Value.Value = ujson.read(s, trace)

  def write(t: Value.Value,
            indent: Int = -1,
            escapeUnicode: Boolean = false): String = ujson.write(t, indent, escapeUnicode)

  def writeTo(t: Value.Value,
              out: java.io.Writer,
              indent: Int = -1,
              escapeUnicode: Boolean = false): Unit = ujson.writeTo(t, out, indent, escapeUnicode)

  def javaObjectFrom(node: ujson.Value): java.lang.Object = node match {
    case Null => null
    case Bool(value) => value.asInstanceOf[java.lang.Boolean]
    case Num(value) => value.asInstanceOf[java.lang.Double]
    case Str(value) => value
    case Obj(value) => value.map(keyVal => (keyVal._1, javaObjectFrom(keyVal._2))).asJava
    case Arr(value) => value.map(javaObjectFrom).asJava
  }

  // Stack safe implementation using Trampolines for deeply nested objects
  // See: https://stackoverflow.com/a/37585818/4814697
  // https://stackoverflow.com/a/55047640/4814697
  def deepJavaObjectFrom(node: Value): java.lang.Object = {
    def tailrecObjFrom(node: Value): TailRec[java.lang.Object] = {
      node match {
        case Null => done(null)
        case Bool(value) => done(value.asInstanceOf[java.lang.Boolean])
        case Num(value) => done(value.asInstanceOf[java.lang.Double])
        case Str(value) => done(value)
        case Obj(value) => value.toList.foldRight(done(List.empty[(String, java.lang.Object)])) {
          (keyVal, tailrecEntrySet) =>
            for {
              entrySet <- tailrecEntrySet
              javaObj <- tailcall(tailrecObjFrom(keyVal._2))
            } yield entrySet.prepended((keyVal._1, javaObj))
        }.map(list => list.toMap.asJava)
        case Arr(value) => value.foldRight(done(List.empty[java.lang.Object])) {
          (item, tailrecList) =>
            for {
              list <- tailrecList
              javaObj <- tailcall(tailrecObjFrom(item))
            } yield list.::(javaObj)
        }.map(list => list.asJava)
      }
    }

    tailrecObjFrom(node).result
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy