{"id":15631264,"url":"https://github.com/julienrf/play-json-derived-codecs","last_synced_at":"2025-10-06T13:38:51.242Z","repository":{"id":12182322,"uuid":"14783265","full_name":"julienrf/play-json-derived-codecs","owner":"julienrf","description":null,"archived":false,"fork":false,"pushed_at":"2024-04-11T07:09:17.000Z","size":135,"stargazers_count":192,"open_issues_count":19,"forks_count":36,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-10-03T22:38:01.790Z","etag":null,"topics":["derivation","json","play-framework"],"latest_commit_sha":null,"homepage":null,"language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/julienrf.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}},"created_at":"2013-11-28T17:47:23.000Z","updated_at":"2025-04-12T13:14:02.000Z","dependencies_parsed_at":"2024-04-11T08:37:05.197Z","dependency_job_id":null,"html_url":"https://github.com/julienrf/play-json-derived-codecs","commit_stats":null,"previous_names":["julienrf/play-json-variants"],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/julienrf/play-json-derived-codecs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/julienrf%2Fplay-json-derived-codecs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/julienrf%2Fplay-json-derived-codecs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/julienrf%2Fplay-json-derived-codecs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/julienrf%2Fplay-json-derived-codecs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/julienrf","download_url":"https://codeload.github.com/julienrf/play-json-derived-codecs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/julienrf%2Fplay-json-derived-codecs/sbom","scorecard":{"id":542172,"data":{"date":"2025-08-11","repo":{"name":"github.com/julienrf/play-json-derived-codecs","commit":"c0061ca45944bf2e4f3c90e93733268588704a0d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.2,"checks":[{"name":"Code-Review","score":4,"reason":"Found 7/15 approved changesets -- score normalized to 4","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:9: update your workflow using https://app.stepsecurity.io/secureworkflow/julienrf/play-json-derived-codecs/ci.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:10: update your workflow using https://app.stepsecurity.io/secureworkflow/julienrf/play-json-derived-codecs/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:11: update your workflow using https://app.stepsecurity.io/secureworkflow/julienrf/play-json-derived-codecs/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:11: update your workflow using https://app.stepsecurity.io/secureworkflow/julienrf/play-json-derived-codecs/release.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/julienrf/play-json-derived-codecs/release.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/julienrf/play-json-derived-codecs/release.yml/master?enable=pin","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   2 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Warn: no topLevel permission defined: .github/workflows/release.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENCE:0","Info: FSF or OSI recognized license: MIT License: LICENCE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 24 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-20T08:28:49.260Z","repository_id":12182322,"created_at":"2025-08-20T08:28:49.260Z","updated_at":"2025-08-20T08:28:49.260Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278621846,"owners_count":26017253,"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","status":"online","status_checked_at":"2025-10-06T02:00:05.630Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["derivation","json","play-framework"],"created_at":"2024-10-03T10:39:45.131Z","updated_at":"2025-10-06T13:38:51.223Z","avatar_url":"https://github.com/julienrf.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"(Note: this project has been renamed from [play-json-variants](https://github.com/julienrf/play-json-variants/tree/v2.0) to `play-json-derived-codecs`)\n\n# Play JSON Derived Codecs [![](https://index.scala-lang.org/julienrf/play-json-derived-codecs/play-json-derived-codecs/latest.svg)](https://index.scala-lang.org/julienrf/play-json-derived-codecs)\n\n`Reads`, `OWrites` and `OFormat` derivation for algebraic data types (sealed traits and case classes, possibly recursive), powered by [shapeless](http://github.com/milessabin/shapeless).\n\nCompared to the built-in macros, this project brings support for:\n\n- sealed traits ;\n- recursive types ;\n- polymorphic types.\n\nThe artifacts are built for Scala and Scala.js 2.12, and 2.13, Play 3.0 and Shapeless 2.3.\n\n## Versions\n\nFor previous versions of Play, you can use previous versions of this library:\n\n| Library version                                                             | Play version    |\n|-----------------------------------------------------------------------------|-----------------|\n| [Latest](https://github.com/julienrf/play-json-derived-codecs/releases)     | 3.0.x           |\n| [10.1.0](https://github.com/julienrf/play-json-derived-codecs/tree/v10.1.0) | 2.9.x           |\n| [7.0.0](https://github.com/julienrf/play-json-derived-codecs/tree/v7.0.0)   | 2.8.x           |\n\n## Usage\n\n~~~ scala\nimport julienrf.json.derived\n\ncase class User(name: String, age: Int)\n\nobject User {\n  implicit val reads: Reads[User] = derived.reads()\n}\n~~~\n\nThe [API](https://www.javadoc.io/doc/org.julienrf/play-json-derived-codecs_2.12) is simple: the object\n`julienrf.json.derived` has just three methods.\n\n- `reads[A]()`, derives a `Reads[A]` ;\n- `owrites[A]()`, derives a `OWrites[A]` ;\n- `oformat[A]()`, derives a `OFormat[A]`.\n\n### Representation of Sum Types\n\nBy default, sum types (types extending a sealed trait) are represented by a JSON object containing\none field whose name is the name of the concrete type and whose value is the JSON object containing\nthe value of the given type.\n\nFor instance, consider the following data type:\n\n~~~ scala\nsealed trait Foo\ncase class Bar(s: String, i: Int) extends Foo\ncase object Baz extends Foo\n~~~\n\nThe default JSON representation of `Bar(\"quux\", 42)` is the following JSON object:\n\n~~~ javascript\n{\n  \"Bar\": {\n    \"s\": \"quux\",\n    \"i\": 42\n  }\n}\n~~~\n\n### Configuring the Derivation Process\n\nThree aspects of the derivation process can be configured:\n\n- the representation of sum types,\n- the way case class field names are mapped to JSON property names,\n- the type name used to discriminate sum types.\n\n#### Custom Representation of Sum Types\n\nThe default representation of sum types may not fit all use cases. For instance, it is not very\npractical for enumerations.\n\nFor instance, you might want to represent the `Bar(\"quux\", 42)` value as the following JSON object:\n\n~~~ javascript\n{\n  \"type\": \"Bar\",\n  \"s\": \"quux\",\n  \"i\": 42\n}\n~~~\n\nHere, the type information is flattened with the `Bar` members.\n\nYou can do so by using the methods in the `derived.flat` object:\n\n~~~ scala\nimplicit val fooOWrites: OWrites[Foo] =\n  derived.flat.owrites((__ \\ \"type\").write[String])\n~~~\n\nIn case you need even more control, you can implement your own `TypeTagOWrites` and `TypeTagReads`.\n\n#### Custom Field Names Mapping\n\nBy default, case class fields are mapped to JSON object properties having the same name.\n\nYou can transform this mapping by supplying a different `NameAdapter` parameter. For\ninstance, to use “snake case” in JSON:\n\n~~~ scala\nimplicit val userFormat: OFormat[User] = derived.oformat(adapter = NameAdapter.snakeCase)\n~~~\n\n#### Custom Type Names\n\nBy default, case class names are used as discriminators (type tags) for sum types.\n\nYou can configure the type tags to use by using the `derived.withTypeTag` object:\n\n~~~ scala\nimplicit val fooFormat: OFormat[Foo] =\n  derived.withTypeTag.oformat(TypeTagSetting.FullClassName)\n~~~\n\nThe library provides the following `TypeTagSetting` values out of the box:\n\n- `TypeTagSetting.ShortClassName`: use the class name (as it is defined in Scala)\n- `TypeTagSetting.FullClassName`: use the fully qualified name\n- `TypeTagSetting.UserDefinedName`: require the presence of an implicit `CustomTypeTag[A]`\n  for all type `A` of the sum type, providing the type tag to use\n\n### Custom format for certain types in hierarchy\n\nSometimes, you might want to represent one type differently than default format would. This can be done by creating an implicit instance of `DerivedReads` or `DerivedWrites` for said type. Below is an example of implementing both custom reads and writes for a single class in a hierarchy:\n\n~~~ scala\nsealed trait Hierarchy\ncase class First(x: Integer)\ncase class Second(y: Integer)\n\nimplicit val SecondReads: DerivedReads[Second] = new DerivedReads[Second] {\n  def reads(tagReads: TypeTagReads, adapter: NameAdapter) = tagReads.reads(\"Second\", (__ \\ \"foo\").read[Integer].map(foo =\u003e Second(foo)))\n}\n\nimplicit val SecondWrites: DerivedOWrites[Second] = new DerivedOWrites[Second] {\n  override def owrites(tagOwrites: TypeTagOWrites, adapter: NameAdapter): OWrites[Second] =\n    tagOwrites.owrites[Second](\n      \"Second\",\n      OWrites[Second](s =\u003e JsObject((\"foo\", Json.toJson(s.y)) :: Nil))\n    )\n}\n\nval defaultTypeFormat = (__ \\ \"type\").format[String]\nimplicit val HierarchyFormat = derived.flat.oformat[Hierarchy](defaultTypeFormat)\n~~~\n\nThis will cause `Second` to be read with `SecondReads`, and read with `SecondWrites`.\n\n### Avoiding redundant derivation\n\nBy default, the auto-derivation mechanism will be applied to the whole sealed hierarchy. This might be costly in terms of compile-time (as Shapeless is being used under the hood).\nTo avoid this, it is possible to define an `Format` for the different cases, thus only using auto-derivation for the branching in the sealed trait and nothing else.\n~~~ scala\nsealed trait Hierarchy\n\ncase class First(a: Int, b: Int, c: Int) extends Hierarchy\ncase class Second(x: Int, y: Int, c: Int) extends Hierarchy\n\nobject First {\n  implicit val format: OFormat[First] = Json.format\n}\n\nobject Second {\n  implicit val format: OFormat[Second] = Json.format\n}\n\nimplicit val HierarchyFormat = derived.oformat[Hierarchy]()\n~~~\n\n**Important note**: in case `derived.flat` is being used, it's recommended that the provided `Format`s actually produce `JsObject`s. If that's not the case, a synthetic wrapper around the user-provided result will be generated on-the-fly.\nFor this reason, `Json.valueFormat` and the like are not compatible with `derived.flat`, and it is best to avoid using them together.\n\nHere is what will happen if they are used together:\n~~~ scala\nsealed trait Foo\ncase class Bar(x: Int) extends Foo\n\nobject Bar {\n  implicit val format: Format[Bar] = Json.valueFormat\n}\n\nimplicit val fooFormat = derived.flat.oformat[Foo]((__ \\ \"type\").format[String])\n\nJson.toJson(Bar(42)) // { \"type\": \"Bar\", \"__syntheticWrap__\": 42 }\n~~~\n\nWithout the provided `Format`s the derivation mechanism will traverse all the fields in the hierarchy (in this case 6 in total), which may be costly for larger case classes.\n\nProviding the implicits this way can also be used for customization without having to deal with supplying your own type-tags.\n\n## Contributors\n\nSee [here](https://github.com/julienrf/play-json-variants/graphs/contributors).\n\n## Changelog\n\nSee [here](https://github.com/julienrf/play-json-derived-codecs/releases).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjulienrf%2Fplay-json-derived-codecs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjulienrf%2Fplay-json-derived-codecs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjulienrf%2Fplay-json-derived-codecs/lists"}