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.
npx @tessl/cli install tessl/maven-io-circe--circe-core@0.14.0Circe is a comprehensive JSON library for Scala that enables developers to encode and decode JSON data with type safety and functional programming principles. The core module contains fundamental data types like Json, JsonObject, JsonNumber, and essential type classes including Encoder, Decoder, and Codec for converting between Scala values and JSON. It offers a cursor-based API for navigating and manipulating JSON structures, comprehensive error handling with detailed failure information, and seamless integration with the Cats functional programming ecosystem.
libraryDependencies += "io.circe" %% "circe-core" % "0.14.13"import io.circe._
import io.circe.syntax._Import specific components:
import io.circe.{Json, JsonObject, JsonNumber, Encoder, Decoder, Codec}
import io.circe.{HCursor, ACursor, DecodingFailure, ParsingFailure}
import io.circe.{Printer, KeyEncoder, KeyDecoder}import io.circe._
import io.circe.syntax._
// Direct JSON construction using factory methods
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))
)
// Using constants and collection builders
val nullValue = Json.Null
val trueValue = Json.True
val falseValue = Json.False
val arrayJson = Json.fromValues(List(Json.fromInt(1), Json.fromInt(2), Json.fromInt(3)))
val objectJson = Json.fromFields(List("key1" -> Json.fromString("value1"), "key2" -> Json.fromInt(42)))import io.circe._
import io.circe.syntax._
// Basic encoding with syntax extension
val name = "John"
val age = 30
val active = true
val nameJson = name.asJson // Json
val ageJson = age.asJson // Json
val activeJson = active.asJson // Json
// Object encoding with key syntax operator
val personJson = Json.obj(
"name" := "John",
"age" := 30,
"active" := true
)
// Type class based encoding
case class Person(name: String, age: Int, active: Boolean)
implicit val personEncoder: Encoder[Person] = Encoder.forProduct3("name", "age", "active")(p => (p.name, p.age, p.active))
val person = Person("John", 30, true)
val encoded = person.asJson // Jsonimport io.circe._
import io.circe.parser._
// Basic decoding
val json = parse("""{"name":"John","age":30,"active":true}""").getOrElse(Json.Null)
val cursor = json.hcursor
val name: Decoder.Result[String] = cursor.downField("name").as[String]
val age: Decoder.Result[Int] = cursor.downField("age").as[Int]
// Object decoding
implicit val personDecoder: Decoder[Person] = Decoder.forProduct3("name", "age", "active")(Person.apply)
val person: Either[DecodingFailure, Person] = json.as[Person]import io.circe._
import io.circe.parser._
val jsonString = """{"users":[{"name":"John","age":30},{"name":"Jane","age":25}]}"""
val json = parse(jsonString).getOrElse(Json.Null)
val cursor = json.hcursor
val firstUserName = cursor
.downField("users")
.downArray
.downField("name")
.as[String] // Right("John")import io.circe._
val json1 = Json.obj("name" := "John", "age" := 30)
val json2 = Json.obj("age" := 31, "city" := "NYC")
// Deep merge JSON objects
val merged = json1.deepMerge(json2) // {"name":"John","age":31,"city":"NYC"}
// Remove null values
val withNulls = Json.obj("name" := "John", "email" := Json.Null, "age" := 30)
val cleaned = withNulls.dropNullValues // {"name":"John","age":30}
// Search for keys
val nested = Json.obj("user" := Json.obj("profile" := Json.obj("name" := "John")))
val names = nested.findAllByKey("name") // List(Json.fromString("John"))
val namesAlt = nested \\ "name" // Alternative syntaximport io.circe._
val json = Json.obj("name" := "John", "age" := 30, "scores" := Json.arr(85, 92, 78))
// Built-in printing options
val compact = json.noSpaces // {"name":"John","age":30,"scores":[85,92,78]}
val pretty = json.spaces2 // Pretty printed with 2-space indentation
val sorted = json.spaces2SortKeys // Pretty printed with sorted keys
// Custom printer
val printer = Printer.noSpaces.copy(dropNullValues = true, sortKeys = true)
val custom = printer.print(json)Circe-core is built around several key abstractions:
Core data structures for representing JSON values with factory methods and manipulation APIs.
sealed abstract class Json {
// Type checking
def isNull: Boolean
def isBoolean: Boolean
def isNumber: Boolean
def isString: Boolean
def isArray: Boolean
def isObject: Boolean
// Pattern matching
def fold[X](
jsonNull: => X,
jsonBoolean: Boolean => X,
jsonNumber: JsonNumber => X,
jsonString: String => X,
jsonArray: Vector[Json] => X,
jsonObject: JsonObject => X
): X
// Manipulation
def deepMerge(that: Json): Json
def dropNullValues: Json
def dropEmptyValues: Json
def findAllByKey(key: String): List[Json]
def \\(key: String): List[Json]
// Printing
def noSpaces: String
def spaces2: String
def spaces4: String
def spaces2SortKeys: String
def printWith(printer: Printer): String
}
object Json {
// Constants
val Null: Json
val True: Json
val False: Json
// Factory methods
def obj(fields: (String, Json)*): Json
def arr(values: Json*): Json
def fromFields(fields: Iterable[(String, Json)]): Json
def fromValues(values: Iterable[Json]): Json
def fromString(value: String): Json
def fromBoolean(value: Boolean): Json
def fromInt(value: Int): Json
def fromLong(value: Long): Json
def fromDouble(value: Double): Json
def fromBigDecimal(value: BigDecimal): Json
}
final case class JsonObject {
def apply(key: String): Option[Json]
def contains(key: String): Boolean
def size: Int
def isEmpty: Boolean
def keys: Iterable[String]
def values: Iterable[Json]
def add(key: String, value: Json): JsonObject
def remove(key: String): JsonObject
def mapValues(f: Json => Json): JsonObject
def deepMerge(that: JsonObject): JsonObject
}
sealed abstract class JsonNumber {
def toBigDecimal: Option[BigDecimal]
def toBigInt: Option[BigInt]
def toDouble: Double
def toLong: Option[Long]
def toInt: Option[Int]
}Type-safe encoding and decoding between Scala types and JSON with combinators and instances.
trait Encoder[A] {
def apply(a: A): Json
def contramap[B](f: B => A): Encoder[B]
def mapJson(f: Json => Json): Encoder[A]
}
object Encoder {
def apply[A](implicit instance: Encoder[A]): Encoder[A]
def instance[A](f: A => Json): Encoder[A]
// Primitive instances
implicit val encodeString: Encoder[String]
implicit val encodeInt: Encoder[Int]
implicit val encodeBoolean: Encoder[Boolean]
implicit val encodeDouble: Encoder[Double]
implicit val encodeBigDecimal: Encoder[BigDecimal]
// Collection instances
implicit def encodeList[A: Encoder]: Encoder[List[A]]
implicit def encodeVector[A: Encoder]: Encoder[Vector[A]]
implicit def encodeSet[A: Encoder]: Encoder[Set[A]]
implicit def encodeMap[A: Encoder]: Encoder[Map[String, A]]
implicit def encodeOption[A: Encoder]: Encoder[Option[A]]
// Subtypes
trait AsObject[A] extends Encoder[A] {
def encodeObject(a: A): JsonObject
}
trait AsArray[A] extends Encoder[A] {
def encodeArray(a: A): Vector[Json]
}
}
trait Decoder[A] {
def apply(c: HCursor): Decoder.Result[A]
def map[B](f: A => B): Decoder[B]
def flatMap[B](f: A => Decoder[B]): Decoder[B]
def emap[B](f: A => Either[String, B]): Decoder[B]
def ensure(pred: A => Boolean, message: => String): Decoder[A]
def at(field: String): Decoder[A]
def prepare(f: ACursor => ACursor): Decoder[A]
}
object Decoder {
type Result[A] = Either[DecodingFailure, A]
type AccumulatingResult[A] = ValidatedNel[DecodingFailure, A]
def apply[A](implicit instance: Decoder[A]): Decoder[A]
def instance[A](f: HCursor => Result[A]): Decoder[A]
def const[A](a: A): Decoder[A]
def failed[A](failure: DecodingFailure): Decoder[A]
// Primitive instances
implicit val decodeString: Decoder[String]
implicit val decodeInt: Decoder[Int]
implicit val decodeBoolean: Decoder[Boolean]
implicit val decodeDouble: Decoder[Double]
implicit val decodeBigDecimal: Decoder[BigDecimal]
// Collection instances (similar to Encoder)
implicit def decodeList[A: Decoder]: Decoder[List[A]]
implicit def decodeVector[A: Decoder]: Decoder[Vector[A]]
implicit def decodeOption[A: Decoder]: Decoder[Option[A]]
implicit def decodeMap[A: Decoder]: Decoder[Map[String, A]]
}
trait Codec[A] extends Decoder[A] with Encoder[A] {
def iemap[B](f: A => Either[String, B])(g: B => A): Codec[B]
}
object Codec {
def from[A](decoder: Decoder[A], encoder: Encoder[A]): Codec[A]
}Zipper-like API for navigating and manipulating JSON structures with path tracking.
abstract class ACursor {
def focus: Option[Json]
def succeeded: Boolean
def failed: Boolean
def history: List[CursorOp]
// Navigation
def top: Option[Json]
def up: ACursor
def left: ACursor
def right: ACursor
def downField(k: String): ACursor
def downArray: ACursor
def downN(n: Int): ACursor
def field(k: String): ACursor
// Modification
def withFocus(f: Json => Json): ACursor
def set(j: Json): ACursor
def delete: ACursor
// Decoding
def as[A](implicit d: Decoder[A]): Decoder.Result[A]
def get[A](k: String)(implicit d: Decoder[A]): Decoder.Result[A]
def getOrElse[A](k: String)(fallback: => A)(implicit d: Decoder[A]): A
}
abstract class HCursor extends ACursor {
def value: Json
def root: HCursor
def keys: Option[Iterable[String]]
def values: Option[Iterable[Json]]
}
object HCursor {
def fromJson(value: Json): HCursor
}
sealed abstract class CursorOp {
def requiresArray: Boolean
def requiresObject: Boolean
}
object CursorOp {
case object MoveLeft extends CursorOp
case object MoveRight extends CursorOp
case object MoveUp extends CursorOp
case object DownArray extends CursorOp
case class DownField(k: String) extends CursorOp
case class DownN(n: Int) extends CursorOp
case class Field(k: String) extends CursorOp
}Comprehensive error types with detailed failure information and path tracking.
sealed abstract class Error extends Exception
final case class ParsingFailure(
message: String,
underlying: Throwable
) extends Error
sealed abstract class DecodingFailure extends Error {
def message: String
def history: List[CursorOp]
def pathToRootString: Option[String]
def reason: DecodingFailure.Reason
def withMessage(message: String): DecodingFailure
def withReason(reason: DecodingFailure.Reason): DecodingFailure
}
object DecodingFailure {
sealed abstract class Reason
object Reason {
case object MissingField extends Reason
case class WrongTypeExpectation(expected: String, got: Json) extends Reason
case class CustomReason(message: String) extends Reason
}
def apply(message: String, ops: List[CursorOp]): DecodingFailure
def apply(message: String, cursor: ACursor): DecodingFailure
}
final case class Errors(errors: NonEmptyList[Error]) extends ExceptionType-safe conversion of object keys between Scala types and strings.
trait KeyEncoder[A] {
def apply(key: A): String
}
trait KeyDecoder[A] {
def apply(key: String): Option[A]
}Configurable JSON formatting and output with extensive customization options.
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,
escapeNonAscii: Boolean,
sortKeys: Boolean,
reuseWriters: Boolean,
predictSize: Boolean
) {
def print(json: Json): String
def printToByteBuffer(json: Json): ByteBuffer
def withSortedKeys: Printer
}
object Printer {
val noSpaces: Printer
val spaces2: Printer
val spaces4: Printer
val noSpacesSortKeys: Printer
val spaces2SortKeys: Printer
val spaces4SortKeys: Printer
def indented(indent: String, sortKeys: Boolean = false): Printer
}object Decoder {
type Result[A] = Either[DecodingFailure, A]
type AccumulatingResult[A] = ValidatedNel[DecodingFailure, A]
}
sealed abstract class CursorOp// Syntax extensions for encoding
implicit class EncoderOps[A](private val value: A) extends AnyVal {
def asJson(implicit encoder: Encoder[A]): Json
def asJsonObject(implicit encoder: Encoder.AsObject[A]): JsonObject
}
// Syntax extensions for object key creation
implicit class KeyOps[K](private val value: K) extends AnyVal {
def :=[A: Encoder](a: A)(implicit keyEncoder: KeyEncoder[K]): (String, Json)
}
// Syntax extensions for JSON values
implicit class JsonOps(private val json: Json) extends AnyVal {
def hcursor: HCursor
def as[A](implicit decoder: Decoder[A]): Decoder.Result[A]
def asAccumulating[A](implicit decoder: Decoder[A]): Decoder.AccumulatingResult[A]
def \\(key: String): List[Json]
def findAllByKey(key: String): List[Json]
}
// Syntax extensions for cursors
implicit class ACursorOps(private val cursor: ACursor) extends AnyVal {
def as[A](implicit decoder: Decoder[A]): Decoder.Result[A]
def get[A](key: String)(implicit decoder: Decoder[A]): Decoder.Result[A]
def getOrElse[A](key: String)(fallback: => A)(implicit decoder: Decoder[A]): A
}