CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-circe--circe-core

Core module of circe, a JSON library for Scala that enables developers to encode and decode JSON data with type safety and functional programming principles.

Pending
Overview
Eval results
Files

json-printing.mddocs/

JSON Printing

Circe provides flexible and configurable JSON printing through the Printer class. It offers various formatting options, performance optimizations, and output formats.

Printer

Configurable JSON pretty-printer for formatting JSON output.

final case class Printer(
  dropNullValues: Boolean,
  indent: String,
  lbraceLeft: String = "",
  lbraceRight: String = "",
  rbraceLeft: String = "",
  rbraceRight: String = "",
  lbracketLeft: String = "",
  lbracketRight: String = "",
  rbracketLeft: String = "",
  rbracketRight: String = "",
  lrbracketsEmpty: String = "",
  arrayCommaLeft: String = "",
  arrayCommaRight: String = "",
  objectCommaLeft: String = "",
  objectCommaRight: String = "",
  colonLeft: String = "",
  colonRight: String = "",
  reuseWriters: Boolean = false,
  predictSize: Boolean = false,
  escapeNonAscii: Boolean = false,
  sortKeys: Boolean = false
) {
  // Core printing methods
  def print(json: Json): String
  def printToByteBuffer(json: Json, cs: Charset): ByteBuffer
  def printToByteBuffer(json: Json): ByteBuffer
  def unsafePrintToAppendable(json: Json, out: Appendable): Unit
  
  // Configuration
  def withSortedKeys: Printer
}

Printer Companion Object

object Printer {
  // Predefined configurations
  val noSpaces: Printer
  val noSpacesSortKeys: Printer
  val spaces2: Printer
  val spaces2SortKeys: Printer
  val spaces4: Printer
  val spaces4SortKeys: Printer
  
  // Custom indentation
  def indented(indent: String, sortKeys: Boolean = false): Printer
}

Usage Examples

Basic Printing

import io.circe._
import io.circe.syntax._

val json = Json.obj(
  "name" -> Json.fromString("John"),
  "age" -> Json.fromInt(30),
  "active" -> Json.fromBoolean(true),
  "scores" -> Json.arr(Json.fromInt(85), Json.fromInt(92), Json.fromInt(78))
)

// Compact printing (no spaces)
val compact = json.noSpaces
// Result: {"name":"John","age":30,"active":true,"scores":[85,92,78]}

// Pretty printing with 2 spaces
val pretty2 = json.spaces2
// Result:
// {
//   "name" : "John",
//   "age" : 30,
//   "active" : true,
//   "scores" : [
//     85,
//     92,
//     78
//   ]
// }

// Pretty printing with 4 spaces
val pretty4 = json.spaces4
// Result:
// {
//     "name" : "John",
//     "age" : 30,
//     "active" : true,
//     "scores" : [
//         85,
//         92,
//         78
//     ]
// }

Custom Printer Configuration

import io.circe._

val json = Json.obj(
  "name" -> Json.fromString("John"),
  "email" -> Json.Null,
  "age" -> Json.fromInt(30)
)

// Custom printer that drops null values
val customPrinter = Printer(
  dropNullValues = true,
  indent = "  ",
  lbraceRight = "\n",
  rbraceLeft = "\n",
  arrayCommaRight = "\n",
  objectCommaRight = "\n",
  colonLeft = " ",
  colonRight = " "
)

val result = customPrinter.print(json)
// Result:
// {
//   "name" : "John",
//   "age" : 30
// }
// Note: "email": null is omitted

Sorted Keys

import io.circe._

val json = Json.obj(
  "zebra" -> Json.fromString("animal"),
  "apple" -> Json.fromString("fruit"),
  "banana" -> Json.fromString("fruit"),
  "ant" -> Json.fromString("insect")
)

// Default order (insertion order)
val unsorted = json.spaces2
// Result:
// {
//   "zebra" : "animal",
//   "apple" : "fruit", 
//   "banana" : "fruit",
//   "ant" : "insect"
// }

// Sorted keys
val sorted = json.printWith(Printer.spaces2SortKeys)
// Result:
// {
//   "ant" : "insect",
//   "apple" : "fruit",
//   "banana" : "fruit", 
//   "zebra" : "animal"
// }

// Or using withSortedKeys
val sortedCustom = Printer.spaces4.withSortedKeys.print(json)

Performance Optimizations

import io.circe._
import java.nio.charset.StandardCharsets

val largeJson = Json.obj(
  "data" -> Json.arr((1 to 1000).map(i => Json.obj(
    "id" -> Json.fromInt(i),
    "value" -> Json.fromString(s"item-$i")
  )): _*)
)

// Reuse writers for better performance in multi-threaded scenarios
val optimizedPrinter = Printer(
  dropNullValues = false,
  indent = "",
  reuseWriters = true,
  predictSize = true
)

// String output
val jsonString = optimizedPrinter.print(largeJson)

// Binary output for network transmission
val byteBuffer = optimizedPrinter.printToByteBuffer(largeJson, StandardCharsets.UTF_8)
val bytes = new Array[Byte](byteBuffer.remaining())
byteBuffer.get(bytes)

Unicode Handling

import io.circe._

val json = Json.obj(
  "message" -> Json.fromString("Hello 世界! 🌍"),
  "emoji" -> Json.fromString("😀 😃 😄 😁")
)

// Default: preserves Unicode characters
val withUnicode = json.noSpaces
// Result: {"message":"Hello 世界! 🌍","emoji":"😀 😃 😄 😁"}

// Escape non-ASCII characters
val unicodeEscaped = Printer(
  dropNullValues = false,
  indent = "",
  escapeNonAscii = true
).print(json)
// Result: {"message":"Hello \\u4e16\\u754c! \\ud83c\\udf0d","emoji":"\\ud83d\\ude00 \\ud83d\\ude03 \\ud83d\\ude04 \\ud83d\\ude01"}

Custom Formatting

import io.circe._

val json = Json.obj(
  "users" -> Json.arr(
    Json.obj("name" -> Json.fromString("Alice")),
    Json.obj("name" -> Json.fromString("Bob"))
  )
)

// Minimal spacing
val minimal = Printer(
  dropNullValues = false,
  indent = "",
  colonRight = " ",
  arrayCommaRight = " ",
  objectCommaRight = " "
).print(json)
// Result: {"users": [{"name": "Alice"}, {"name": "Bob"}]}

// Custom indentation with tabs
val tabIndented = Printer(
  dropNullValues = false,
  indent = "\t",
  lbraceRight = "\n",
  rbraceLeft = "\n",
  lbracketRight = "\n", 
  rbracketLeft = "\n",
  arrayCommaRight = "\n",
  objectCommaRight = "\n",
  colonLeft = " ",
  colonRight = " "
).print(json)
// Uses tabs for indentation

// No spacing around arrays
val compactArrays = Printer(
  dropNullValues = false,
  indent = "  ",
  lbraceRight = "\n",
  rbraceLeft = "\n",
  objectCommaRight = "\n",
  colonLeft = " ",
  colonRight = " "
  // Arrays remain compact: no lbracketRight/rbracketLeft
).print(json)

Working with Appendable

import io.circe._
import java.io.StringWriter

val json = Json.obj("message" -> Json.fromString("Hello World"))

// Write to StringBuilder
val builder = new StringBuilder()
Printer.noSpaces.unsafePrintToAppendable(json, builder)
val result1 = builder.toString

// Write to StringWriter
val writer = new StringWriter()
Printer.spaces2.unsafePrintToAppendable(json, writer)
val result2 = writer.toString

// Write to any Appendable
class CustomAppendable extends Appendable {
  private val buffer = new StringBuilder()
  
  def append(csq: CharSequence): Appendable = {
    buffer.append(csq)
    this
  }
  
  def append(csq: CharSequence, start: Int, end: Int): Appendable = {
    buffer.append(csq, start, end)
    this
  }
  
  def append(c: Char): Appendable = {
    buffer.append(c)
    this
  }
  
  def getResult: String = buffer.toString
}

val custom = new CustomAppendable()
Printer.noSpaces.unsafePrintToAppendable(json, custom)
val result3 = custom.getResult

Binary Output

import io.circe._
import java.nio.charset.{Charset, StandardCharsets}
import java.nio.ByteBuffer

val json = Json.obj(
  "text" -> Json.fromString("Hello"),
  "number" -> Json.fromInt(42)
)

// UTF-8 output (default)
val utf8Buffer = Printer.noSpaces.printToByteBuffer(json)
val utf8Bytes = new Array[Byte](utf8Buffer.remaining())
utf8Buffer.get(utf8Bytes)
val utf8String = new String(utf8Bytes, StandardCharsets.UTF_8)

// UTF-16 output
val utf16Buffer = Printer.noSpaces.printToByteBuffer(json, StandardCharsets.UTF_16)
val utf16Bytes = new Array[Byte](utf16Buffer.remaining())
utf16Buffer.get(utf16Bytes)
val utf16String = new String(utf16Bytes, StandardCharsets.UTF_16)

// ASCII with escaped Unicode
val asciiPrinter = Printer(
  dropNullValues = false,
  indent = "",
  escapeNonAscii = true
)
val asciiBuffer = asciiPrinter.printToByteBuffer(json, StandardCharsets.US_ASCII)

Error Handling in Printing

import io.circe._

// Printing generally doesn't fail, but here are edge cases
val problematicJson = Json.fromDouble(Double.NaN)

problematicJson match {
  case Some(json) => 
    val printed = json.noSpaces
    println(s"Printed: $printed")
  case None =>
    println("Cannot create JSON from NaN")
}

// Infinite values
val infiniteJson = Json.fromDouble(Double.PositiveInfinity)
infiniteJson match {
  case Some(json) => 
    val printed = json.noSpaces
    println(s"Printed: $printed") // "null"
  case None =>
    println("Cannot create JSON from infinite value")
}

Streaming and Large JSON

import io.circe._
import java.io.{FileWriter, BufferedWriter}

// For very large JSON, use unsafePrintToAppendable with a buffered writer
val largeJson = Json.obj(
  "items" -> Json.arr(
    (1 to 100000).map(i => Json.obj(
      "id" -> Json.fromInt(i),
      "data" -> Json.fromString(s"data-$i")
    )): _*
  )
)

// Write directly to file
val fileWriter = new BufferedWriter(new FileWriter("large.json"))
try {
  Printer.noSpaces.unsafePrintToAppendable(largeJson, fileWriter)
} finally {
  fileWriter.close()
}

// Or use ByteBuffer for binary output
val buffer = Printer.noSpaces.printToByteBuffer(largeJson)
// Can write buffer to FileChannel, SocketChannel, etc.

Printer Performance Comparison

import io.circe._

val testJson = Json.obj(
  "data" -> Json.arr((1 to 1000).map(Json.fromInt): _*)
)

// Compact printing (fastest)
val compact = Printer.noSpaces
val compactResult = compact.print(testJson)

// Pretty printing (slower due to whitespace)
val pretty = Printer.spaces2
val prettyResult = pretty.print(testJson)

// With optimizations (fastest for repeated use)
val optimized = Printer(
  dropNullValues = false,
  indent = "",
  reuseWriters = true,
  predictSize = true
)
val optimizedResult = optimized.print(testJson)

// With sorted keys (slowest due to sorting)
val sorted = Printer.noSpacesSortKeys
val sortedResult = sorted.print(testJson)

Install with Tessl CLI

npx tessl i tessl/maven-io-circe--circe-core

docs

cursor-navigation.md

error-handling.md

index.md

json-data-types.md

json-printing.md

key-encoding-decoding.md

type-classes.md

tile.json