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.
—
Circe provides flexible and configurable JSON printing through the Printer class. It offers various formatting options, performance optimizations, and output formats.
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
}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
}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
// ]
// }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 omittedimport 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)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)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"}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)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.getResultimport 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)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")
}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.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