{"id":13801520,"url":"https://github.com/typelevel/jawn","last_synced_at":"2025-05-14T03:11:17.252Z","repository":{"id":4869420,"uuid":"6024359","full_name":"typelevel/jawn","owner":"typelevel","description":"Jawn is for parsing jay-sawn (JSON)","archived":false,"fork":false,"pushed_at":"2025-04-25T06:01:06.000Z","size":4968,"stargazers_count":435,"open_issues_count":14,"forks_count":74,"subscribers_count":21,"default_branch":"main","last_synced_at":"2025-05-07T13:22:44.341Z","etag":null,"topics":["json","scala"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/typelevel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2012-10-01T02:04:45.000Z","updated_at":"2025-04-25T06:01:09.000Z","dependencies_parsed_at":"2023-07-05T17:00:58.806Z","dependency_job_id":"384b3f66-bd3a-4956-8b23-31152ac9b172","html_url":"https://github.com/typelevel/jawn","commit_stats":{"total_commits":882,"total_committers":50,"mean_commits":17.64,"dds":0.753968253968254,"last_synced_commit":"ef365fcffb1e2738e2c9d93362b50acaed33205e"},"previous_names":["non/jawn"],"tags_count":50,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelevel%2Fjawn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelevel%2Fjawn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelevel%2Fjawn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelevel%2Fjawn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/typelevel","download_url":"https://codeload.github.com/typelevel/jawn/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254059518,"owners_count":22007771,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["json","scala"],"created_at":"2024-08-04T00:01:23.816Z","updated_at":"2025-05-14T03:11:17.197Z","avatar_url":"https://github.com/typelevel.png","language":"Scala","readme":"## Jawn\n\n\"Jawn is for parsing jay-sawn.\"\n\n### Origin\n\nThe term \"jawn\" comes from the Philadelphia area. It conveys about as\nmuch information as \"thing\" does. I chose the name because I had moved\nto Montreal so I was remembering Philly fondly. Also, there isn't a\nbetter way to describe objects encoded in JSON than \"things\". Finally,\nwe get a catchy slogan.\n\nJawn was designed to parse JSON into an AST as quickly as possible.\n\n![](https://github.com/typelevel/jawn/workflows/Scala/badge.svg)\n[![Latest version](https://index.scala-lang.org/typelevel/jawn/jawn-parser/latest.svg?color=orange)](https://index.scala-lang.org/typelevel/jawn/jawn-parser)\n\n### Overview\n\nJawn consists of three parts:\n\n1. A fast, generic JSON parser (`jawn-parser`)\n2. A small, somewhat anemic AST (`jawn-ast`)\n3. A few helpful utilities (`jawn-util`)\n\nCurrently Jawn is competitive with the fastest Java JSON libraries\n(GSON and Jackson) and in the author's benchmarks it often wins. It\nseems to be faster than any other Scala parser that exists (as of July\n2014).\n\nGiven the plethora of really nice JSON libraries for Scala, the\nexpectation is that you're probably here for `jawn-parser` or a\nsupport package.\n\n### Quick Start\n\nJawn supports Scala 2.12, 2.13, and 3 on the JVM and Scala.js.  Scala\n2.12 and 2.13 are supported on Scala Native.\n\nHere's a `build.sbt` snippet that shows you how to depend on Jawn in\nyour own sbt project:\n\n```scala\n// use this if you just want jawn's parser, and will implement your own facade\nlibraryDependencies += \"org.typelevel\" %% \"jawn-parser\" % \"1.3.2\"\n\n// use this if you want jawn's parser and also jawn's ast\nlibraryDependencies += \"org.typelevel\" %% \"jawn-ast\" % \"1.3.2\"\n```\n\nIf you want to use Jawn's parser with another project's AST, see the\n\"Supporting external ASTs with Jawn\" section.  There are a few reasons\nyou might want to do this:\n\n * The library's built-in parser is significantly slower than Jawn's.\n * Jawn supports more input types (`ByteBuffer`, `File`, etc.).\n * You need asynchronous JSON parsing.\n\n### Dependencies\n\n*jawn-parser* has no dependencies other than Scala.\n\n*jawn-ast* depends on *jawn-parser* but nothing else.\n\n### Parsing\n\nJawn's parser is both fast and relatively featureful. Assuming you\nwant to get back an AST of type `J` and you have a `Facade[J]`\ndefined, you can use the following `parse` signatures:\n\n```scala\nParser.parseUnsafe[J](String) → J\nParser.parseFromString[J](String) → Try[J]\nParser.parsefromPath[J](String) → Try[J]\nParser.parseFromFile[J](File) → Try[J]\nParser.parseFromChannel[J](ReadableByteChannel) → Try[J]\nParser.parseFromByteBuffer[J](ByteBuffer) → Try[J]\n```\n\nJawn also supports asynchronous parsing, which allows users to feed\nthe parser with data as it is available. There are three modes:\n\n* `SingleValue` waits to return a single `J` value once parsing is done.\n* `UnwrapArray` if the top-level element is an array, return values as they become available. Set `multiValue` to `true`\nif you want to support multiple top level arrays.\n* `ValueStream` parse one-or-more json values separated by whitespace.\n\nHere's an example:\n\n```scala\nimport org.typelevel.jawn.ast\nimport org.typelevel.jawn.AsyncParser\nimport org.typelevel.jawn.ParseException\n\nval p = ast.JParser.async(mode = AsyncParser.UnwrapArray)\n\ndef chunks: Stream[String] = ???\ndef sink(j: ast.JValue): Unit = ???\n\ndef loop(st: Stream[String]): Either[ParseException, Unit] =\n  st match {\n    case s #:: tail =\u003e\n      p.absorb(s) match {\n        case Right(js) =\u003e\n          js.foreach(sink)\n          loop(tail)\n        case Left(e) =\u003e\n          Left(e)\n      }\n    case _ =\u003e\n      p.finish().right.map(_.foreach(sink))\n  }\n\nloop(chunks)\n```\n\nYou can also call `Parser.async[J]` to use async parsing with an\narbitrary data type (provided you also have an implicit `Facade[J]`).\n\n### Supporting external ASTs with Jawn\n\n#### Circe\n\n[circe] is supported via its [`circe-parser`](https://circe.github.io/circe/parsing.html) module.\n\n#### Argonaut\n\n[argonaut] is supported via its `argonaut-jawn` module.\n\n### Do-It-Yourself Parsing\n\nJawn supports building any JSON AST you need via type classes. You\nbenefit from Jawn's fast parser while still using your favorite Scala\nJSON library. This mechanism is also what allows Jawn to provide\n\"support\" for other libraries' ASTs.\n\nTo include Jawn's parser in your project, add the following\nsnippet to your `build.sbt` file:\n\n```scala\nresolvers += Resolver.sonatypeRepo(\"releases\")\n\nlibraryDependencies += \"org.typelevel\" %% \"jawn-parser\" % \"1.3.2\"\n```\n\nTo support your AST of choice, you'll want to define a `Facade[J]`\ninstance, where the `J` type parameter represents the base of your JSON\nAST. For example, here's a facade that supports Spray:\n\n```scala\nimport spray.json._\nobject Spray extends SimpleFacade[JsValue] {\n  def jnull() = JsNull\n  def jfalse() = JsFalse\n  def jtrue() = JsTrue\n  def jnum(s: String) = JsNumber(s)\n  def jint(s: String) = JsNumber(s)\n  def jstring(s: String) = JsString(s)\n  def jarray(vs: List[JsValue]) = JsArray(vs)\n  def jobject(vs: Map[String, JsValue]) = JsObject(vs)\n}\n```\n\nMost ASTs will be easy to define using the `SimpleFacade` or\n`MutableFacade` traits. However, if an ASTs object or array instances\ndo more than just wrap a Scala collection, it may be necessary to\nextend `Facade` directly.\n\nExtend `SupportParser[J]`, supplying your facade as the abstract\n`facade`, to get convenient methods for parsing various input types or\nan `AsyncParser`.\n\n### Using the AST\n\n#### Access\n\nFor accessing atomic values, `JValue` supports two sets of\nmethods: *get-style* methods and *as-style* methods.\n\nThe *get-style* methods return `Some(_)` when called on a compatible\nJSON value (e.g. strings can return `Some[String]`, numbers can return\n`Some[Double]`, etc.), and `None` otherwise:\n\n```scala\ngetBoolean → Option[Boolean]\ngetString → Option[String]\ngetLong → Option[Long]\ngetDouble → Option[Double]\ngetBigInt → Option[BigInt]\ngetBigDecimal → Option[BigDecimal]\n```\n\nIn constrast, the *as-style* methods will either return an unwrapped\nvalue (instead of returning `Some(_)`) or throw an exception (instead\nof returning `None`):\n\n```scala\nasBoolean → Boolean // or exception\nasString → String // or exception\nasLong → Long // or exception\nasDouble → Double // or exception\nasBigInt → BigInt // or exception\nasBigDecimal → BigDecimal // or exception\n```\n\nTo access elements of an array, call `get` with an `Int` position:\n\n```scala\nget(i: Int) → JValue // returns JNull if index is illegal\n```\n\nTo access elements of an object, call `get` with a `String` key:\n\n```scala\nget(k: String) → JValue // returns JNull if key is not found\n```\n\nBoth of these methods also return `JNull` if the value is not the\nappropraite container. This allows the caller to chain lookups without\nhaving to check that each level is correct:\n\n```scala\nval v: JValue = ???\n\n// returns JNull if a problem is encountered in structure of 'v'.\nval t: JValue = v.get(\"novels\").get(0).get(\"title\")\n\n// if 'v' had the right structure and 't' is JString(s), then Some(s).\n// otherwise, None.\nval titleOrNone: Option[String] = t.getString\n\n// equivalent to titleOrNone.getOrElse(throw ...)\nval titleOrDie: String = t.asString\n```\n\n#### Updating\n\nThe atomic values (`JNum`, `JBoolean`, `JNum`, and `JString`) are\nimmutable.\n\nObjects are fully-mutable and can have items added, removed, or\nchanged:\n\n```scala\nset(k: String, v: JValue) → Unit\nremove(k: String) → Option[JValue]\n```\n\nIf `set` is called on a non-object, an exception will be thrown.\nIf `remove` is called on a non-object, `None` will be returned.\n\nArrays are semi-mutable. Their values can be changed, but their size\nis fixed:\n\n```scala\nset(i: Int, v: JValue) → Unit\n```\n\nIf `set` is called on a non-array, or called with an illegal index, an\nexception will be thrown.\n\n(A future version of Jawn may provide an array whose length can be\nchanged.)\n\n### Profiling\n\nJawn uses [JMH](http://openjdk.java.net/projects/code-tools/jmh/)\nalong with the [sbt-jmh](https://github.com/ktoso/sbt-jmh) plugin.\n\n#### Running Benchmarks\n\nThe benchmarks are located in the `benchmark` project. You can run the\nbenchmarks by typing `benchmark/jmh:run` from SBT. There are many\nsupported arguments, so here are a few examples:\n\nRun all benchmarks, with 10 warmups, 10 iterations, using 3 threads:\n\n`benchmark/jmh:run -wi 10 -i 10 -f1 -t3`\n\nRun just the `CountriesBench` test (5 warmups, 5 iterations, 1 thread):\n\n`benchmark/jmh:run -wi 5 -i 5 -f1 -t1 .*CountriesBench`\n\n#### Benchmark Issues\n\nCurrently, the benchmarks are a bit fiddily. The most obvious symptom\nis that if you compile the benchmarks, make changes, and compile\nagain, you may see errors like:\n\n```\n[error] (benchmark/jmh:generateJavaSources) java.lang.NoClassDefFoundError: jawn/benchmark/Bla25Bench\n```\n\nThe fix here is to run `benchmark/clean` and try again.\n\nYou will also see intermittent problems like:\n\n```\n[error] (benchmark/jmh:compile) java.lang.reflect.MalformedParameterizedTypeException\n```\n\nThe solution here is easier (though frustrating): just try it\nagain. If you continue to have problems, consider cleaning the project\nand trying again.\n\n(In the future I hope to make the benchmarking here a bit more\nresilient. Suggestions and pull requests gladly welcome!)\n\n#### Files\n\nThe benchmarks use files located in `benchmark/src/main/resources`. If\nyou want to test your own files (e.g. `mydata.json`), you would:\n\n * Copy the file to `benchmark/src/main/resources/mydata.json`.\n * Add the following code to `JmhBenchmarks.scala`:\n\n```scala\nclass MyDataBench extends JmhBenchmarks(\"mydata.json\")\n```\n\nJawn has been tested with much larger files, e.g. 100M - 1G, but these\nare obviously too large to ship with the project.\n\nWith large files, it's usually easier to comment out most of the\nbenchmarking methods and only test one (or a few) methods. Some of the\nslower JSON parsers get *much* slower for large files.\n\n#### Interpreting the results\n\nRemember that the benchmarking results you see will vary based on:\n\n * Hardware\n * Java version\n * JSON file size\n * JSON file structure\n * JSON data values\n\nI have tried to use each library in the most idiomatic and fastest way\npossible (to parse the JSON into a simple AST). Pull requests to\nupdate library versions and improve usage are very welcome.\n\n### Future Work\n\nMore support libraries could be added.\n\nIt's likely that some of Jawn's I/O could be optimized a bit more, and\nalso made more configurable. The heuristics around all-at-once loading\nversus input chunking could definitely be improved.\n\nIn cases where the user doesn't need fast lookups into JSON objects,\nan even lighter AST could be used to improve parsing and rendering\nspeeds.\n\nStrategies to cache/intern field names of objects could pay big\ndividends in some cases (this might require AST changes).\n\nIf you have ideas for any of these (or other ideas) please feel free\nto open an issue or pull request so we can talk about it.\n\n### Disclaimers\n\nJawn only supports UTF-8 when parsing bytes. This might change in the\nfuture, but for now that's the target case. You can always decode your\ndata to a string, and handle the character set decoding using Java's\nstandard tools.\n\nJawn's AST is intended to be very lightweight and simple. It supports\nsimple access, and limited mutable updates. It intentionally lacks the\npower and sophistication of many other JSON libraries.\n\n### Community\n\nPeople are expected to follow the\n[Scala Code of Conduct](https://scala-lang.org/conduct/) when\ndiscussing Jawn on GitHub or other venues.\n\nJawn's current maintainers are:\n\n * [Ross A. Baker](https://github.com/rossabaker)\n * [Travis Brown](https://github.com/travisbrown)\n * [Erik Osheim](https://github.com/non)\n * [Dale Wijnand](https://github.com/dwijnand)\n * [Eugene Yokota](https://github.com/eed3si9n)\n\n### Copyright and License\n\nAll code is available to you under the MIT license, available at\nhttp://opensource.org/licenses/mit-license.php.\n\nCopyright Erik Osheim, 2012-2022.\n\n[circe]: https://circe.github.io/circe/\n[argonaut]: http://argonaut.io\n","funding_links":[],"categories":["Table of Contents"],"sub_categories":["JSON"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftypelevel%2Fjawn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftypelevel%2Fjawn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftypelevel%2Fjawn/lists"}