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

io.gatling.core.json.Json.scala Maven / Gradle / Ivy

/*
 * Copyright 2011-2018 GatlingCorp (https://gatling.io)
 *
 * 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.
 */

package io.gatling.core.json

import java.lang.{ StringBuilder => JStringBuilder }
import java.util.{ Collection => JCollection, Map => JMap }

import scala.annotation.switch
import scala.collection.JavaConverters._

import io.gatling.commons.util.HexUtils
import io.gatling.commons.util.Maps._
import io.gatling.netty.util.ahc.StringBuilderPool
import io.gatling.commons.util.Spire._

object Json {

  private val stringBuilders = new StringBuilderPool

  def stringify(value: Any, isRootObject: Boolean = true): String = {

    val sb = stringBuilders.get()

    def appendStringified(value: Any, rootLevel: Boolean): JStringBuilder = value match {
      case b: Byte                   => sb.append(b)
      case s: Short                  => sb.append(s)
      case i: Int                    => sb.append(i)
      case l: Long                   => sb.append(l)
      case f: Float                  => sb.append(f)
      case d: Double                 => sb.append(d)
      case bool: Boolean             => sb.append(bool)
      case s: String                 => appendString(s, rootLevel)
      case null                      => sb.append("null")
      case map: collection.Map[_, _] => appendMap(map)
      case jMap: JMap[_, _]          => appendMap(jMap.asScala)
      case array: Array[_]           => appendArray(array)
      case seq: Seq[_]               => appendArray(seq)
      case coll: JCollection[_]      => appendArray(coll.asScala)
      case _                         => appendString(value.toString, rootLevel)
    }

    def appendString(s: String, rootLevel: Boolean): JStringBuilder =
      if (rootLevel) {
        appendString0(s)
      } else {
        sb.append('"')
        appendString0(s).append('"')
      }

    def appendString0(s: String): JStringBuilder = {
      cfor(0)(_ < s.length, _ + 1) { i =>
        val c = s.charAt(i)
        c match {
          case '"'  => sb.append("\\\"")
          case '\\' => sb.append("\\\\")
          case '\b' => sb.append("\\b")
          case '\f' => sb.append("\\f")
          case '\n' => sb.append("\\n")
          case '\r' => sb.append("\\r")
          case '\t' => sb.append("\\t")
          case _ =>
            if (Character.isISOControl(c)) {
              sb.append("\\u")
              var n: Int = c
              cfor(0)(_ < 4, _ + 1) { _ =>
                val digit = (n & 0xf000) >> 12
                sb.append(HexUtils.toHexChar(digit))
                n <<= 4
              }
            } else {
              sb.append(c)
            }
        }
      }
      sb
    }

    def appendArray(iterable: Traversable[_]): JStringBuilder = {
      sb.append('[')
      iterable.foreach { elem =>
        appendStringified(elem, rootLevel = false).append(',')
      }
      if (iterable.nonEmpty) {
        sb.setLength(sb.length - 1)
      }
      sb.append(']')
    }

    def appendMap(map: collection.Map[_, _]): JStringBuilder = {
      sb.append('{')
      map.foreach {
        case (k, v) =>
          sb.append('"').append(k).append("\":")
          appendStringified(v, rootLevel = false).append(',')
      }
      if (map.nonEmpty) {
        sb.setLength(sb.length - 1)
      }
      sb.append('}')
    }

    appendStringified(value, isRootObject).toString
  }

  def asScala(value: Any): Any =
    value match {
      case list: JCollection[_] => list.asScala.map(asScala)
      case map: JMap[_, _] =>
        (map.size: @switch) match {
          case 0 => Map.empty
          case 1 =>
            val entry0 = map.entrySet.iterator.next()
            new Map.Map1(entry0.getKey, asScala(entry0.getValue))
          case 2 =>
            val it = map.entrySet.iterator
            val entry0 = it.next()
            val entry1 = it.next()
            new Map.Map2(
              entry0.getKey, asScala(entry0.getValue),
              entry1.getKey, asScala(entry1.getValue)
            )
          case 3 =>
            val it = map.entrySet.iterator
            val entry0 = it.next()
            val entry1 = it.next()
            val entry2 = it.next()
            new Map.Map3(
              entry0.getKey, asScala(entry0.getValue),
              entry1.getKey, asScala(entry1.getValue),
              entry2.getKey, asScala(entry2.getValue)
            )
          case 4 =>
            val it = map.entrySet.iterator
            val entry0 = it.next()
            val entry1 = it.next()
            val entry2 = it.next()
            val entry3 = it.next()
            new Map.Map4(
              entry0.getKey, asScala(entry0.getValue),
              entry1.getKey, asScala(entry1.getValue),
              entry2.getKey, asScala(entry2.getValue),
              entry3.getKey, asScala(entry3.getValue)
            )
          case _ =>
            map.asScala.toMap.forceMapValues(asScala)
        }

      case _ => value
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy