Working with JSON

JSON is widely used throughout HTTP APIs nowadays and it is also one of the most commonly used data formats for the Vert.x EventBus. That makes good JSON support essential. This page describes how to construct, read and alter JSON objects and arrays with the Vert.x for Scala API.

Builders & Interpolators

Creating JsonObject and JsonArray instances is easily done using either the builder API in io.vertx.lang.scala.json.Json or the custom String Interpolator in the package object io.vertx.lang.scala.json.

JsonObject

JsonObjects can be built via a builder or via an interpolator:


import io.vertx.lang.scala.json.Json
import io.vertx.lang.scala.json.json
// Json.obj takes...
// ...a vararg of Scala Tuples
val fromVararg = Json.obj(
  "foo" -> "foo text",
  "bar" -> 3.45d,
  "baz" -> false,
  "myInt" -> Integer.MAX_VALUE)

// ...or a Scala Map
val fromMap = Json.obj(Map("foo" -> "foo text", "bar" -> 3.45d))

// ...or a String
val fromString = Json.obj(
  """
    |{
    |  "foo": "foo text",
    |  "bar": 3.45,
    |  "baz": false,
    |  "myInt": 2147483647
    |}
  """.stripMargin)

// Additionally, the json interpolator can be used:
val bar = 3.45
val myInt = 2147483647
val fromInterpolator =
  json"""
        {
          "foo": "foo text",
          "bar": $bar,
          "baz": false,
          "myInt": $myInt
        }"""

JsonArray

JSON arrays are built similarly:

import collection.immutable.SortedSet
import io.vertx.lang.scala.json.Json.arr
import io.vertx.lang.scala.json.jsonArray
// Json.arr takes...
// a vararg of values
val fromVararg = arr("4", "8", "15", "16", "23", "42")

// ...or a Seq
val fromSeq = arr(List("108", "216"))

// ...or a Set
val fromSet = arr(SortedSet(4, 8, 15, 16, 23, 42))

// ...or a String
val fromString = arr("[4, 8, 15, 16, 23, 42]")

// Additionally, the jsonArray interpolator can be used:
val fortytwo = 42
val fromInterpolator = jsonArray"[4, 8, 15, 16, 23, $fortytwo]"

Nesting

Any Iterable can be nested to create a JsonObject containing a JsonArray. Also any Map can be nested in order to create a JsonArray containing JsonObjects:

import io.vertx.lang.scala.json.Json.*
// Nesting a JsonArray in a JsonObject
val nestedArray = obj("k1" -> 42, "k2" -> List(3, 2, 1))
// res1: JsonObject = {"k1":42,"k2":[3,2,1]}

// ...and vice versa
val nestedObject = arr(1, 2, 3, Map("k1" -> 42, "k2" -> "bar"))
// res2: JsonArray = [1,2,3,{"k1":42,"k2":"bar"}]

Deep nesting can be achieved by subsequent usage of Json.obj() or Json.arr():

import io.vertx.core.json.JsonObject
import io.vertx.lang.scala.json.Json
import io.vertx.lang.scala.json.Json.{arr, obj}
Json.obj(
        "webappconf" -> obj(
          "port" -> 8080,
          "ssl" -> false,
          "bridge" -> true,
          "some_nested" -> Vector(1, 2, obj("next" -> List(3, 4))),
          "some_list" -> arr(1, 2, Vector(3, 4)),
          "inbound_permitted" -> List(
            obj(
              "address" -> "acme.bar",
              "match" -> obj(
                "action" -> "foo")),
            obj(
              "address" -> "acme.baz",
              "match" -> obj(
                "action" -> "index"))),
          "outbound_permitted" -> Array(new JsonObject())))

From JsonObject and JsonArray to Map and List

Converting from existing JsonObject or JsonArray instances to Scala Map or List is supported by extension methods defined in the package io.vertx.lang.scala.json:

Json Pointers

Vert.x for Scala provides the io.vertx.lang.scala.json.JsonPointer, which is a Scala wrapper for io.vertx.core.json.pointer.JsonPointer from core Vert.x. The wrapper's benefits are typesafe as well as immutable operations.

To build a JsonPointer, use its apply method:

import io.vertx.lang.scala.json.JsonPointer
val pointer1 = JsonPointer("/hello/world")
val pointer2 = JsonPointer() // root pointer
  .appended("hello")
  .appended("world")

Querying

After instantiation, the query method can be used to query a value from a JsonObject or JsonArray.

Note: The type argument must be supplied when calling this method to indicate the desired return type:

import io.vertx.lang.scala.json.*
val json =
  json"""{
    "hello": {
      "world": "¡Hola, mundo!"
    },
    "numbers": [4, 8, 15, 16, 23, 42]
  }"""
val worldPtr = JsonPointer("/hello/world")
val numbrPtr = JsonPointer("/numbers/5")
val spanish  = worldPtr.query[String](json).getOrElse("¡Perdón!") // "¡Hola, mundo!"
val fortytwo = numbrPtr.query[Double](json).getOrElse(0)          // 42
// the following query won't work because the expected return type is wrong
val wontwork = numbrPtr.query[String](json)                       // None

Writing

The write method can be used to add or update values in a JsonObject or JsonArray.

Note: For JsonArrays values can only be added. It is currently impossible to change a value. If required, create a new array.

Note: The write method will return a new JsonObject or JsonArray. The original one will be left untouched.

import io.vertx.lang.scala.json.*
val json =
  json"""{
    "hello": {
      "world": "¡Hola, mundo!"
    },
    "numbers": [4, 8, 15, 16, 23, 42]
  }"""
val moonPtr      = JsonPointer("/hello/moon")
val firstElement = JsonPointer("/numbers/0")
val arrayPtr     = JsonPointer("/numbers")
moonPtr.write(json, "¡Hola, Luna!")                   // adds "moon": "¡Hola, Luna!"
firstElement.write(json, 0)                           // adds 0, resulting in [0, 4, 8, 15, 16, 23, 42]
arrayPtr.write(json, Json.arr(0, 8, 15, 16, 23, 42))  // replaces 4 with 0, resulting [0, 8, 15, 16, 23, 42]