{"id":13906376,"url":"https://github.com/jvican/dijon","last_synced_at":"2025-03-17T16:09:44.903Z","repository":{"id":14855187,"uuid":"17578395","full_name":"jvican/dijon","owner":"jvican","description":"A Dynamically Typed Scala Json Library","archived":false,"fork":false,"pushed_at":"2024-08-13T00:57:27.000Z","size":37250,"stargazers_count":182,"open_issues_count":15,"forks_count":13,"subscribers_count":11,"default_branch":"master","last_synced_at":"2024-10-12T09:25:21.091Z","etag":null,"topics":["dynamic-types","json","scala","scala-json-library"],"latest_commit_sha":null,"homepage":null,"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/jvican.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}},"created_at":"2014-03-10T01:30:07.000Z","updated_at":"2024-08-25T04:10:27.000Z","dependencies_parsed_at":"2023-02-16T01:31:33.245Z","dependency_job_id":"2a9d8c6d-1754-46d3-9515-407adabfccd6","html_url":"https://github.com/jvican/dijon","commit_stats":null,"previous_names":["pathikrit/dijon"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jvican%2Fdijon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jvican%2Fdijon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jvican%2Fdijon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jvican%2Fdijon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jvican","download_url":"https://codeload.github.com/jvican/dijon/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244066179,"owners_count":20392406,"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":["dynamic-types","json","scala","scala-json-library"],"created_at":"2024-08-06T23:01:34.547Z","updated_at":"2025-03-17T16:09:44.878Z","avatar_url":"https://github.com/jvican.png","language":"Scala","funding_links":[],"categories":["Scala"],"sub_categories":[],"readme":"![Continuous Integration](https://github.com/jvican/dijon/workflows/Continuous%20Integration/badge.svg?branch=master)\n\ndijon - Dynamic JSON in Scala\n=====\n* Boiler-free JSON wrangling using Scala [Dynamic Types](https://www.scala-lang.org/api/2.13.2/scala/Dynamic.html)\n* Support of [RFC8259](https://tools.ietf.org/html/rfc8259) using a codec based on [jsoniter-scala-core][2] that [passes all JSONTestSuite checks](https://github.com/nst/JSONTestSuite/pull/99)\n* Why yet another Scala JSON library? Well, code speaks more than thousand words:\n\n```scala\nval (name, age) = (\"Tigri\", 7)\nval cat = json\"\"\"\n  {\n    \"name\": \"$name\",\n    \"age\": $age,\n    \"hobbies\": [\"eating\", \"purring\"],\n    \"is cat\": true\n  }\n\"\"\"\nassert(cat.name == name)                         // dynamic type\nassert(cat.age == age)\nval Some(catAge: Int) = cat.age.asInt\nassert(catAge == age)\nassert(cat.age.asBoolean == None)\n\nval catMap = cat.toMap                           // view as a hashmap\nassert(catMap.toMap.keysIterator.toSeq == Seq(\"name\", \"age\", \"hobbies\", \"is cat\"))\n\nassert(cat.hobbies(1) == \"purring\") // array access\nassert(cat.hobbies(100) == None)    // missing element\nassert(cat.`is cat` == true)        // keys with spaces/symbols/scala-keywords need to be escaped with ticks\nassert(cat.email == None)           // missing key\n\nval vet = `{}`                      // create empty json object\nvet.name = \"Dr. Kitty Specialist\"   // set attributes in json object\nvet.phones = `[]`                   // create empty json array\nval phone = \"(650) 493-4233\"\nvet.phones(2) = phone               // set the 3rd item in array to this phone\nassert(vet.phones == mutable.Seq(None, None, phone))  // first 2 entries None\n\nvet.address = `{}`\nvet.address.name = \"Animal Hospital\"\nvet.address.city = \"Palo Alto\"\nvet.address.zip = 94306\nassert(vet.address == mutable.Map[String, SomeJson](\"name\" -\u003e \"Animal Hospital\", \"city\" -\u003e \"Palo Alto\", \"zip\" -\u003e 94306))\n\ncat.vet = vet                            // set the cat.vet to be the vet json object we created above\nassert(cat.vet.phones(2) == phone)\nassert(cat.vet.address.zip == 94306)     // json deep access\n\nprintln(cat) // {\"name\":\"Tigri\",\"age\":7,\"hobbies\":[\"eating\",\"purring\"],\"is cat\":true,\"vet\":{\"name\":\"Dr. Kitty Specialist\",\"phones\":[null,null,\"(650) 493-4233\"],\"address\":{\"name\":\"Animal Hospital\",\"city\":\"Palo Alto\",\"zip\":94306}}}\n\nassert(cat == parse(cat.toString))   // round-trip test\n\nvar basicCat = cat -- \"vet\"                                  // remove 1 key\nbasicCat = basicCat -- (\"hobbies\", \"is cat\", \"paws\")         // remove multiple keys (\"paws\" is not in cat)\nassert(basicCat == json\"\"\"{ \"name\": \"Tigri\", \"age\": 7}\"\"\")   // after dropping some keys above\n```\n\n* Simple deep-merging:\n```scala\nval scala = json\"\"\"\n{\n  \"name\": \"scala\",\n  \"version\": \"2.13.2\",\n  \"features\": {\n    \"functional\": true,\n    \"awesome\": true\n  }\n}\n\"\"\"\n\nval java = json\"\"\"\n{\n  \"name\": \"java\",\n  \"features\": {\n    \"functional\": [0, 0],\n    \"terrible\": true\n  },\n  \"bugs\": 213\n}\n\"\"\"\n\nval scalaCopy = scala.deepCopy\nval javaCopy = java.deepCopy\n\nassert((scala ++ java) == json\"\"\"{\"name\":\"java\",\"version\":\"2.13.2\",\"features\":{\"functional\":[0,0],\"terrible\":true,\"awesome\":true},\"bugs\":213}\"\"\")\nassert((java ++ scala) == json\"\"\"{\"name\":\"scala\",\"version\":\"2.13.2\",\"features\":{\"functional\": true,\"terrible\":true,\"awesome\":true},\"bugs\":213}\"\"\")\n\nassert(scala == scalaCopy)       // original json objects stay untouched after merging\nassert(java == javaCopy)\n```\n\n* [Union types](dijon/src/main/scala/dijon/UnionType.scala) for [type-safety](dijon/src/main/scala/dijon/package.scala#L11):\n```scala\nval json = `{}`\njson.aString = \"hi\"                        // compiles\njson.aBoolean = true                       // compiles\njson.anInt = 23                            // compiles\n//json.somethingElse = Option(\"hi\")       // does not compile\nval Some(i: Int) = json.anInt.asInt\nassert(i == 23)\nassert(json.aBoolean.asInt == None)\n```\n\n* `obj()` and `arr()` constructor functions for building up complex JSON values with less overhead:\n```scala\nval rick = obj(\n  \"name\" -\u003e name,\n  \"age\" -\u003e age,\n  \"class\" -\u003e \"human\",\n  \"weight\" -\u003e 175.1,\n  \"is online\" -\u003e true,\n  \"contact\" -\u003e obj(\n    \"emails\" -\u003e arr(email1, email2),\n    \"phone\" -\u003e obj(\n      \"home\" -\u003e \"817-xxx-xxx\",\n      \"work\" -\u003e \"650-xxx-xxx\"\n    )\n  ),\n  \"hobbies\" -\u003e arr(\n    \"eating\",\n    obj(\n      \"games\" -\u003e obj(\n        \"chess\" -\u003e true,\n        \"football\" -\u003e false\n      )\n    ),\n    arr(\"coding\", arr(\"python\", \"scala\")),\n    None\n  ),\n  \"toMap\" -\u003e arr(23, 345, true),\n  \"apply\" -\u003e 42\n)\n```\n\nSee the [spec][1] for more examples.\n\nAlso, for the `dijon.codec` an additional functionality is available when using [jsoniter-scala-core][2], like:\n* parsing/serialization from/to byte arrays, byte buffers, and input/output streams\n* parsing of [streamed JSON values](https://en.wikipedia.org/wiki/JSON_streaming) (concatenated or delimited by \n  whitespace characters) and JSON arrays from input streams using callbacks without the need of holding a whole input in\n  the memory\n* use a custom configuration for parsing and serializing  \n  \nSee [jsoniter-scala-core spec][3] for more details and code samples.\n\nUsage\n===\n1. Add the following to your `build.sbt`:\n```scala\nlibraryDependency += \"me.vican.jorge\" %% \"dijon\" % \"0.6.0\" // Use %%% instead of %% for Scala.js\n```\n2. Turn on support of dynamic types by adding import clause:\n```scala\nimport scala.language.dynamics._\n```\nor by setting the scala compiler option:\n```scala\nscalacOptions += \"-language:dynamics\"\n```\n3. Add import of the package object of `dijon` for the main functionality:\n```scala\nimport dijon._\n```\n4. Optionally, add import of package object of `jsoniter-scala-core` for extended json functionality:\n```scala\nimport com.github.plokhotnyuk.jsoniter_scala.core._\n```\n\nTODO\n====\n* BigInt support\n* Circular references checker\n* YAML interpolator\n* Macro for type inference to induce compile-time errors where possible\n* JSON string interpolator fills in braces, quotes and commas etc\n\n[1]: dijon/src/test/scala/dijon/DijonSpec.scala\n[2]: https://github.com/plokhotnyuk/jsoniter-scala/blob/master/jsoniter-scala-core/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/package.scala\n[3]: https://github.com/plokhotnyuk/jsoniter-scala/blob/master/jsoniter-scala-core/src/test/scala/com/github/plokhotnyuk/jsoniter_scala/core/PackageSpec.scala\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjvican%2Fdijon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjvican%2Fdijon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjvican%2Fdijon/lists"}