JSON to Scala case classes with circe
In Scala, JSON models are usually case classes, and circe is one of the most popular libraries for encoding and decoding them. This JSON to Scala generator writes Scala 3 case classes from a sample and, in full mode, adds derives Encoder.AsObject, Decoder to each one, so circe can convert them without any hand-written codecs.
Example
{ "id": 42, "title": "Write docs", "done": false,
"owner": { "name": "Ada", "email": null },
"subtasks": [ { "title": "Outline", "estimate": 2 }, { "title": "Draft" } ] }
package quicktype
import io.circe.syntax._
import io.circe._
case class Task (
val id : Long,
val title : String,
val done : Boolean,
val owner : Owner,
val subtasks : Seq[Subtask]
) derives Encoder.AsObject, Decoder
case class Subtask (
val title : String,
val estimate : Option[Long] = None
) derives Encoder.AsObject, Decoder
The optional estimate is Option[Long] with a default of None. The derives clause is Scala 3 syntax; it asks the compiler to generate circe's type class instances.
How types are inferred
Whole numbers become Long, decimals Double, arrays Seq[T] and nested objects their own case classes. Scala 3 union types are used for mixed values: an array of numbers and strings becomes Seq[X] with type X = Long | String, and the generated codecs handle both alternatives. Fields missing from some objects are wrapped in Option with a None default, so you can construct instances without them in tests.
Decoding and encoding
import io.circe.parser.decode
import io.circe.syntax._
val result: Either[io.circe.Error, Task] = decode[Task](jsonString)
result.foreach(task => println(task.asJson.spaces2))
Add circe-core, circe-generic and circe-parser to your build. Decoding returns an Either, so a mismatch produces a DecodingFailure with the path to the offending field instead of an exception.
Notes and adjustments
- Scala 2:
derivesis not available. Remove it and useio.circe.generic.auto._orderiveDecoder/deriveEncoderfrom circe-generic. valin parameters is redundant for case classes and can be removed.- Dates stay
String; circe has built-in codecs forjava.timetypes such asOffsetDateTimeif you change the field type. - Null-only fields become
Option[Json]; replace them with a concreteOptiontype when you know it. - Other libraries: the plain case classes work with Play JSON, ZIO JSON or uPickle with their own derivation mechanisms.
For a JVM alternative, JSON to Kotlin or JSON to Java produce equivalent models. Validate input with the JSON Validator. Generation runs in your browser.