{"id":13801543,"url":"https://github.com/playframework/play-json","last_synced_at":"2025-05-14T07:09:05.263Z","repository":{"id":37269859,"uuid":"75692093","full_name":"playframework/play-json","owner":"playframework","description":"The Play JSON library","archived":false,"fork":false,"pushed_at":"2025-04-29T13:49:57.000Z","size":2202,"stargazers_count":365,"open_issues_count":59,"forks_count":136,"subscribers_count":15,"default_branch":"main","last_synced_at":"2025-05-08T03:37:20.863Z","etag":null,"topics":["automatic-conversion","convenience-macros","dsl","json","json-ast","playframework","scala","scalajs","serialization","serializer"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/playframework.png","metadata":{"funding":{"github":["playframework"],"open_collective":"playframework"},"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2016-12-06T03:45:35.000Z","updated_at":"2025-05-03T18:10:36.000Z","dependencies_parsed_at":"2023-10-12T21:43:16.806Z","dependency_job_id":"70ea0aa9-068d-4829-ac76-8dafc5f0c85f","html_url":"https://github.com/playframework/play-json","commit_stats":{"total_commits":868,"total_committers":72,"mean_commits":"12.055555555555555","dds":0.782258064516129,"last_synced_commit":"55861ca0c01685c49c7e34478494b86209bcbd8b"},"previous_names":[],"tags_count":69,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/playframework%2Fplay-json","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/playframework%2Fplay-json/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/playframework%2Fplay-json/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/playframework%2Fplay-json/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/playframework","download_url":"https://codeload.github.com/playframework/play-json/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254043068,"owners_count":22004910,"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":["automatic-conversion","convenience-macros","dsl","json","json-ast","playframework","scala","scalajs","serialization","serializer"],"created_at":"2024-08-04T00:01:24.102Z","updated_at":"2025-05-14T07:09:05.217Z","avatar_url":"https://github.com/playframework.png","language":"Scala","readme":"# Play JSON\n\n[![Twitter Follow](https://img.shields.io/twitter/follow/playframework?label=follow\u0026style=flat\u0026logo=twitter\u0026color=brightgreen)](https://twitter.com/playframework)\n[![Discord](https://img.shields.io/discord/931647755942776882?logo=discord\u0026logoColor=white)](https://discord.gg/g5s2vtZ4Fa)\n[![GitHub Discussions](https://img.shields.io/github/discussions/playframework/playframework?\u0026logo=github\u0026color=brightgreen)](https://github.com/playframework/playframework/discussions)\n[![StackOverflow](https://img.shields.io/static/v1?label=stackoverflow\u0026logo=stackoverflow\u0026logoColor=fe7a16\u0026color=brightgreen\u0026message=playframework)](https://stackoverflow.com/tags/playframework)\n[![YouTube](https://img.shields.io/youtube/channel/views/UCRp6QDm5SDjbIuisUpxV9cg?label=watch\u0026logo=youtube\u0026style=flat\u0026color=brightgreen\u0026logoColor=ff0000)](https://www.youtube.com/channel/UCRp6QDm5SDjbIuisUpxV9cg)\n[![Twitch Status](https://img.shields.io/twitch/status/playframework?logo=twitch\u0026logoColor=white\u0026color=brightgreen\u0026label=live%20stream)](https://www.twitch.tv/playframework)\n[![OpenCollective](https://img.shields.io/opencollective/all/playframework?label=financial%20contributors\u0026logo=open-collective)](https://opencollective.com/playframework)\n\n[![Build Status](https://github.com/playframework/play-json/actions/workflows/build-test.yml/badge.svg)](https://github.com/playframework/play-json/actions/workflows/build-test.yml)\n[![Maven](https://img.shields.io/maven-central/v/org.playframework/play-json_2.13.svg?logo=apache-maven)](https://mvnrepository.com/artifact/org.playframework/play-json_2.13)\n[![Repository size](https://img.shields.io/github/repo-size/playframework/play-json.svg?logo=git)](https://github.com/playframework/play-json)\n[![Scala Steward badge](https://img.shields.io/badge/Scala_Steward-helping-blue.svg?style=flat\u0026logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAMAAAARSr4IAAAAVFBMVEUAAACHjojlOy5NWlrKzcYRKjGFjIbp293YycuLa3pYY2LSqql4f3pCUFTgSjNodYRmcXUsPD/NTTbjRS+2jomhgnzNc223cGvZS0HaSD0XLjbaSjElhIr+AAAAAXRSTlMAQObYZgAAAHlJREFUCNdNyosOwyAIhWHAQS1Vt7a77/3fcxxdmv0xwmckutAR1nkm4ggbyEcg/wWmlGLDAA3oL50xi6fk5ffZ3E2E3QfZDCcCN2YtbEWZt+Drc6u6rlqv7Uk0LdKqqr5rk2UCRXOk0vmQKGfc94nOJyQjouF9H/wCc9gECEYfONoAAAAASUVORK5CYII=)](https://scala-steward.org)\n[![Mergify Status](https://img.shields.io/endpoint.svg?url=https://api.mergify.com/v1/badges/playframework/play-json\u0026style=flat)](https://mergify.com)\n\nPlay JSON is a powerful Scala JSON library, originally developed by the Play team for use with Play Framework. It uses Jackson for JSON parsing and has no Play dependencies.\n\nWe've provided some documentation here on how to use Play JSON in your app (without Play). For more information on how to use Play JSON in Play, please refer to the [Play documentation](https://www.playframework.com/documentation/2.8.x/ScalaJson).\n\n## Getting Started\n\nTo get started, you can add play-json as a dependency in your project:\n\n* sbt\n  ```scala\n  libraryDependencies += \"org.playframework\" %% \"play-json\" % -version-\n  ```\n* Gradle\n  ```\n  compile group: 'org.playframework', name: 'play-json_2.13', version: -version-\n  ```\n* Maven\n  ```xml\n  \u003cdependency\u003e\n    \u003cgroupId\u003eorg.playframework\u003c/groupId\u003e\n    \u003cartifactId\u003eplay-json_2.13\u003c/artifactId\u003e\n    \u003cversion\u003e-version-\u003c/version\u003e\n  \u003c/dependency\u003e\n  ```\n\nSee [GitHub releases](https://github.com/playframework/play-json/releases) for the correct version.\n \nPlay JSON supports Scala 2.12, 2.13 and Scala 3.3+. Choosing the right JAR is automatically managed in sbt. If you're using Gradle or Maven then you need to use the correct version in the `artifactId`.\n\n## JSON AST\n\nThe base type in Play JSON is `play.api.libs.json.JsValue`, and has several subtypes representing different JSON types:\n - `JsObject`: a JSON object, represented as a Map. Can be constructed from an ordered `Seq` or any kind of `Map` using `JsObject.apply`\n - `JsArray`: a JSON array, consisting of a `Seq[JsValue]`\n - `JsNumber`: a JSON number, represented as a `BigDecimal`.\n - `JsString`: a JSON string.\n - `JsBoolean`: a JSON boolean, either `JsTrue` or `JsFalse`.\n - `JsNull`: the JSON `null` value.\n\nThe `play.api.libs.json` package includes several features for constructing JSON from scratch, as well as for converting to and from case classes.\n\n## Basic reading and writing\n\nThe `play.api.libs.json.Json` object has several methods for reading and writing:\n\n`Json.parse` parses a JSON string or `InputStream` into a JSON tree:\n\n```scala\nval json: JsValue = Json.parse(\"\"\"\n{\n  \"name\" : \"Watership Down\",\n  \"location\" : {\n    \"lat\" : 51.235685,\n    \"long\" : -1.309197\n  },\n  \"residents\" : [ {\n    \"name\" : \"Fiver\",\n    \"age\" : 4,\n    \"role\" : null\n  }, {\n    \"name\" : \"Bigwig\",\n    \"age\" : 6,\n    \"role\" : \"Owsla\"\n  } ]\n}\n\"\"\")\n```\n\nand `Json.stringify` is used to convert a `JsValue` to a `String` of JSON:\n\n```scala\nval jsonString = Json.stringify(json)\n// {\"name\":\"Watership Down\",\"location\":{\"lat\":51.235685,\"long\":-1.309197},\"residents\":[{\"name\":\"Fiver\",\"age\":4,\"role\":null},{\"name\":\"Bigwig\",\"age\":6,\"role\":\"Owsla\"}]}\n```\n\n## Traversing a `JsValue`\n\nPlay JSON provides a traversal DSL that lets you query fields in the JSON:\n\n### Simple path \\\nApplying the `\\` operator will return the property corresponding to the field argument, supposing this is a JsObject.\n\n```scala\nval lat = (json \\ \"location\" \\ \"lat\").get\n// returns JsNumber(51.235685)\n```\n\nThe `(json \\ \"location\" \\ \"lat\")` returns a `JsLookupResult` which may or may not contain a value. Note that the `get` operation is not always safe; it throws an exception if the path doesn't exist.\n\nYou can also use `\\` to look up indices within a `JsArray`:\n\n```scala\nval bigwig = (json \\ \"residents\" \\ 1).get\n// returns {\"name\":\"Bigwig\",\"age\":6,\"role\":\"Owsla\"}\n```\n\n### Recursive path `\\\\`\nApplying the `\\\\` operator will do a lookup for the field in the current object and all descendants.\n\n```scala\nval names = json \\\\ \"name\"\n// returns Seq(JsString(\"Watership Down\"), JsString(\"Fiver\"), JsString(\"Bigwig\"))\n```\n\n### Index lookup\nYou can retrieve a value in a JsObject or JsArray using an apply operator with the index number or key.\n\n```scala\nval name = json(\"name\")\n// returns JsString(\"Watership Down\")\n\nval bigwig = json(\"residents\")(1)\n// returns {\"name\":\"Bigwig\",\"age\":6,\"role\":\"Owsla\"}\n```\n\nLike `get`, this will throw an exception if the index doesn't exist. Use the Simple Path `\\` operator and `validate` or `asOpt` (described below) if you expect that they key may not be present.\n\n## Reading and writing objects\n\nTo convert a Scala object to and from JSON, we use `Json.toJson[T: Writes]` and `Json.fromJson[T: Reads]` respectively. Play JSON provides the `Reads` and `Writes` typeclasses to define how to read or write specific types. You can get these either by using Play's automatic JSON macros, or by manually defining them.\n\nYou can also read JSON from a `JsValue` using `validate`, `as` and `asOpt` methods. Generally it's preferable to use `validate` since it returns a `JsResult` which may contain an error if the JSON is malformed.\n\nFor example:\n```scala\nval unsafeName = (json \\ \"name\").as[String]\n// \"Watership Down\"\n\nval unsafeBogusName = (json \\ \"bogus\").as[String]\n// throws exception\n\nval nameOption = (json \\ \"name\").asOpt[String]\n// Some(\"Watership Down\")\n\nval bogusOption = (json \\ \"bogus\").asOpt[String]\n// None\n\nval nameResult = (json \\ \"name\").validate[String]\n// JsSuccess(\"Watership Down\")\n\nval bogusResult = (json \\ \"bogus\").validate[String]\n// JsError\n\nval unsafeName2 = json(\"name\").as[String]\n// \"Watership Down\"\n\nval unsafeBogusName2 = json(\"bogus\").as[String]\n// throws exception\n\n```\n\n### Automatic conversion\n\nUsually you don't need to traverse JSON AST directly. Play JSON comes equipped with some convenient macros to convert to and from case classes.\n\nFor example, suppose I have the following class:\n\n```scala\ncase class Resident(name: String, age: Int, role: Option[String])\n```\n\nI can define a `Reads` (JSON parser), `Writes` (JSON writer) using convenient macros:\n\n```scala\nimplicit val residentReads = Json.reads[Resident]\nimplicit val residentWrites = Json.writes[Resident]\n```\nI can also define a `Format` that does both:\n\n```scala\nimplicit val residentFormat = Json.format[Resident]\n```\n\nWith the `Reads` and/or `Writes` in scope, I can then easily convert my class using `toJson` and `fromJson`\n\n### Constructing `Reads` and `Writes`\n\nPlay JSON provides a convenient functional DSL for constructing `Reads` and `Writes`. For example, assume I have the following classes:\n\n```scala\ncase class Location(lat: Double, long: Double)\ncase class Resident(name: String, age: Int, role: Option[String])\ncase class Place(name: String, location: Location, residents: Seq[Resident])\n```\n\nThen I could construct `Reads` for them as follows:\n\n```scala\nimport play.api.libs.json._\nimport play.api.libs.json.Reads._\nimport play.api.libs.functional.syntax._\n\nimplicit val locationReads: Reads[Location] = (\n  (JsPath \\ \"lat\").read[Double](min(-90.0) keepAnd max(90.0)) and\n  (JsPath \\ \"long\").read[Double](min(-180.0) keepAnd max(180.0))\n)(Location.apply _)\n\nimplicit val residentReads: Reads[Resident] = (\n  (JsPath \\ \"name\").read[String](minLength[String](2)) and\n  (JsPath \\ \"age\").read[Int](min(0) keepAnd max(150)) and\n  (JsPath \\ \"role\").readNullable[String]\n)(Resident.apply _)\n\nimplicit val placeReads: Reads[Place] = (\n  (JsPath \\ \"name\").read[String](minLength[String](2)) and\n  (JsPath \\ \"location\").read[Location] and\n  (JsPath \\ \"residents\").read[Seq[Resident]]\n)(Place.apply _)\n\n\nval json = { ... }\n\njson.validate[Place] match {\n  case s: JsSuccess[Place] =\u003e {\n    val place: Place = s.get\n    // do something with place\n  }\n  case e: JsError =\u003e {\n    // error handling flow\n  }\n}\n```\n\nSimilarly, I could construct `Writes` like this:\n\n```scala\nimport play.api.libs.json._\nimport play.api.libs.functional.syntax._\n\nimplicit val locationWrites: Writes[Location] = (\n  (JsPath \\ \"lat\").write[Double] and\n  (JsPath \\ \"long\").write[Double]\n)(unlift(Location.unapply))\n\nimplicit val residentWrites: Writes[Resident] = (\n  (JsPath \\ \"name\").write[String] and\n  (JsPath \\ \"age\").write[Int] and\n  (JsPath \\ \"role\").writeNullable[String]\n)(unlift(Resident.unapply))\n\nimplicit val placeWrites: Writes[Place] = (\n  (JsPath \\ \"name\").write[String] and\n  (JsPath \\ \"location\").write[Location] and\n  (JsPath \\ \"residents\").write[Seq[Resident]]\n)(unlift(Place.unapply))\n\n\nval place = Place(\n  \"Watership Down\",\n  Location(51.235685, -1.309197),\n  Seq(\n    Resident(\"Fiver\", 4, None),\n    Resident(\"Bigwig\", 6, Some(\"Owsla\"))\n  )\n)\n\nval json = Json.toJson(place)\n```\n\nIt is also possible to implement custom logic by implementing the `Reads`, `Writes` and/or `Format` traits manually, but we recommend using the automatic conversion macros or the functional DSL if possible.\n\n### Manual JSON construction\n\nJSON can also be manually constructed using a DSL:\n\n```scala\nval json: JsValue = Json.obj(\n  \"name\" -\u003e \"Watership Down\",\n  \"location\" -\u003e Json.obj(\"lat\" -\u003e 51.235685, \"long\" -\u003e -1.309197),\n  \"residents\" -\u003e Json.arr(\n    Json.obj(\n      \"name\" -\u003e \"Fiver\",\n      \"age\" -\u003e 4,\n      \"role\" -\u003e JsNull\n    ),\n    Json.obj(\n      \"name\" -\u003e \"Bigwig\",\n      \"age\" -\u003e 6,\n      \"role\" -\u003e \"Owsla\"\n    )\n  )\n)\n```\n\n## Releasing a new version\n\nSee https://github.com/playframework/.github/blob/main/RELEASING.md\n\n## License\n\nPlay JSON is licensed under the Apache license, version 2. See the LICENSE file for more information.\n","funding_links":["https://github.com/sponsors/playframework","https://opencollective.com/playframework"],"categories":["Table of Contents","JSON"],"sub_categories":["JSON"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplayframework%2Fplay-json","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fplayframework%2Fplay-json","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplayframework%2Fplay-json/lists"}