{"id":13498313,"url":"https://github.com/infinum/kotlin-jsonapix","last_synced_at":"2026-01-11T16:59:13.862Z","repository":{"id":37856293,"uuid":"291043190","full_name":"infinum/kotlin-jsonapix","owner":"infinum","description":"JsonApiX is an Android, annotation processor library that was made to transform regular Kotlin classes into their JSON API representations, with the ability to serialize or deserialize them to or from strings.","archived":false,"fork":false,"pushed_at":"2024-12-13T11:33:50.000Z","size":859,"stargazers_count":39,"open_issues_count":7,"forks_count":8,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-03-25T04:06:53.711Z","etag":null,"topics":["android","json","json-api","kotlin","open-source"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","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/infinum.png","metadata":{"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}},"created_at":"2020-08-28T12:39:13.000Z","updated_at":"2025-02-25T16:59:22.000Z","dependencies_parsed_at":"2023-09-28T11:28:14.893Z","dependency_job_id":"3bb87ff1-5421-4616-bcfe-03bca4c93ecb","html_url":"https://github.com/infinum/kotlin-jsonapix","commit_stats":null,"previous_names":["infinum/android-jsonapix"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infinum%2Fkotlin-jsonapix","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infinum%2Fkotlin-jsonapix/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infinum%2Fkotlin-jsonapix/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infinum%2Fkotlin-jsonapix/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/infinum","download_url":"https://codeload.github.com/infinum/kotlin-jsonapix/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246125321,"owners_count":20727408,"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":["android","json","json-api","kotlin","open-source"],"created_at":"2024-07-31T21:00:21.930Z","updated_at":"2025-09-20T00:34:06.786Z","avatar_url":"https://github.com/infinum.png","language":"Kotlin","funding_links":[],"categories":["Uncategorized"],"sub_categories":["Uncategorized"],"readme":"![Maven Central Version](https://img.shields.io/maven-central/v/com.infinum.jsonapix/processor?style=plastic)\n\n\n### \u003cimg align=\"left\" src=\"logo.svg\" width=\"48\"\u003e\n# JsonApiX\n\n## Description\n\n- JSON API X is an Android, annotation processor library with the intention of extending it to a KMP library in due time\n- Implements a parser between Kotlin classes and JSON API specification strings in both directions\n- Includes Retrofit module for easy API implementations\n\n## Table of contents\n\n* [Requirements](#requirements)\n* [Getting started](#getting-started)\n* [Usage](#usage)\n* [JsonApiModel - Handling `links` and `meta` JSON API fields](#jsonapimodel---handling-links-and-meta-json-api-fields)\n* [Retrofit Support](#retrofit-support)\n* [List of libraries used in the project](#list-of-libraries-used-in-the-project)\n* [Contributing](#contributing)\n* [License](#license)\n* [Credits](#credits)\n\n## Requirements\n\nThe library uses KAPT for annotation processing.\nThe setup is different on a Kotlin or Java project.\n\n## Getting started\n\nFirstly, make sure to include `mavenCentral()` in your buildscript and add the serialization plugin:\n\n```groovy\nbuildscript {\n    repositories {\n        mavenCentral()\n    }\n\n    dependencies {\n        classpath(\"org.jetbrains.kotlin:kotlin-serialization:$kotlinVersion\")\n    }\n}\n```\n\nThen add the following dependencies and enable `kapt` and `kotlinx-serialization` plugins:\n\n```groovy\nplugins {\n    id \"kotlinx-serialization\"\n    id \"kotlin-kapt\"\n}\n```\n\n```groovy\n// Serialization API. Check the docs link above for newer versions\nimplementation(\"org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.0\")\n\n// Json API X\nimplementation(\"com.infinum.jsonapix:core:\u003clatest-version\u003e\")\n\n// Kotlin project\nkapt(\"com.infinum.jsonapix:processor:\u003clatest-version\u003e\")\n\n// Java project\nannotationProcessor \"com.infinum.jsonapix:processor:\u003clatest-version\u003e\"\n\n// Optional: For Retrofit support\nimplementation(\"com.infinum.jsonapix:retrofit:\u003clatest-version\u003e\")\n\n// Optional: Custom lint tool checker\nimplementation(\"com.infinum.jsonapix:lint:\u003clatest-version\u003e\")\n\n\n```\n\n## Usage\n\nLet's take the example of a class named `Person`.\n\n```kotlin\n@Serializable\n@JsonApiX(type = \"person\")\ndata class Person(\n    val firstName: String,\n    val lastName: String,\n    val age: Int,\n    @HasMany(type = \"friend\")\n    val friends: List\u003cFriend\u003e,\n    @HasOne(type = \"dog\")\n    val dog: Dog?\n)\n```\n\n`@JsonApiX` annotation takes a String type parameter and it must be combined with `@Serializable` from KotlinX Serialization. Type is later\nused as a value for the `type` key in the JSON API specification.\n\n`@HasOne` and `@HasMany` indicate the class relationships. They also take the type parameter, that must be the same as the one indicated in\nthe class definition.\n\nIn this case, `Dog` must also be annotated with `@Serializable` and `@JsonApiX(type = \"dog\")`, where `\"dog\"` is the type defined for\nthe `Dog` class.\n\nAll non-primitive fields of a class should be some kind of relationship.\n\nOnce you hit build, `PersonModel`, `PersonItem`, and `PersonList` are automatically generated. These wrappers facilitate the serialization and deserialization of your classes into and from JSON API strings.\n\nFor example, for a single `Person` instance, `PersonModel` is generated as follows:\n```kotlin\npublic data class PersonModel(\n  public val `data`: Person, // The Person object\n  // ... Root values\n  // ... Resource object values\n)\n```\n```kotlin\npublic data class PersonItem(\n  public val `data`: Person, // Individual Person object within the list\n  // ... Resource object values\n)\n```\n```kotlin\npublic data class PersonList(\n  public val `data`: List\u003cPersonItem\u003e, // List of PersonItem objects\n  // ... Root values\n)\n```\n\nTo access the serialization and deserialization features, you need to use the `TypeAdapter` interface. To get the type adapter for your\nspecific class, use the generated `TypeAdapterFactory`:\n\n```kotlin\n// Gets adapter for a single instance of Person\nval adapter = TypeAdapterFactory().getAdapter(PersonModel::class)\n\n// Gets adapter for a list of Person instances\nval listAdapter = TypeAdapterFactory().getAdapter(PersonList::class)\n\nadapter.convertToString(personModel) // Produces JSON API String from a PersonModel instance\nadapter.convertFromString(inputJsonString) // Produces PersonModel instance from JSON API String\n\nlistAdapter.convertToString(personList) // Produces JSON API String from a PersonList\nlistAdapter.convertFromString(inputJsonString) // Produces PersonList from JSON API String\n```\n\n### Nullability\n\nJsonApiX relies on the `included` JSON array from the JSON API specification when deserializing relationships. If the input JSON API string\nis missing the data of a non-nullable relationship in the `included` array, deserialization attempt will throw\na `JsonApiXMissingArgumentException`. On the other hand, nullable relationships will be evaluated as `null`.\n\n### Errors\n\nAccording to the JSON API specification, each object has an optional error array. The following interface is used as a root-level wrapper\nfor JSON API responses. It contains a nullable `errors` list, that is used to parse the errors.\n\n```kotlin\ninterface JsonApiX\u003cout Model\u003e {\n    val data: ResourceObject\u003cModel\u003e?\n    val included: List\u003cResourceObject\u003c*\u003e\u003e?\n    val errors: List\u003cError\u003e?\n    val links: Links?\n    val meta: Meta?\n}\n```\n\nA single error is modeled to wrap the most common arguments of an error. Developer needs to make sure to model the error responses to match\nthis model.\n\n```kotlin\n@Serializable\n@SerialName(\"error\")\nclass DefaultError(\n    val code: String,\n    val title: String,\n    val detail: String,\n    val status: String\n)\n```\n\nWhen using Retrofit, in the event of a network error a `HttpException` will be thrown. To extract the `DefaultError` model from a response, you can\nuse the `HttpException.asJsonXHttpException()` extension. The extension will return a `JsonXHttpException`, containing the original `response` as well as `errors` list.\n\n```kotlin\n// Using DefaultError\ntry {\n    val person = io { sampleApiService.fetchPerson() }\n} catch (exception: HttpException) {\n    val jsonXHttpException = exception.asJsonXHttpException()\n    val errors = jsonXHttpException.errors // List\u003cDefaultError\u003e\n    // handle errors\n    ...\n}\n```\n\n### Custom error\n\nDevelopers can define their own custom error models to adapt to the specific requirements.\n\nLet's take this custom person error model as an example. \nEvery custom error model should extend the `Error` interface and have a `JsonApiXError` annotation set. \n\n```kotlin\n@Serializable\n@JsonApiXError(type = \"person\")\ndata class PersonalError(\n    val desc: String\n) : Error\n```\n\nIn this example, the annotation processor will automatically make the error type of a `Person` class to be a `PersonError` and use it as a type when deserializing errors array. Developer needs to make sure that the `type` parameter value in `JsonApiXError` matches the one in the `JsonApiX` above the original model.\n\nTo extract a custom error model (ex. `PersonalError`), clients should use a generic `asJsonXHttpException` in a similar way as explained in the previous chapter for `DefaultError`.\n\n```kotlin\n// Using custom error\ntry {\n    val person = io { sampleApiService.fetchPerson() }\n} catch (exception: HttpException) {\n    val jsonXHttpException = exception.asJsonXHttpException\u003cPersonError\u003e()\n    val errors = jsonXHttpException.errors // List\u003cPersonError\u003e\n    // handle errors\n    ...\n}\n```\n\n## JsonApiModel - Handling `links` and `meta` JSON API fields\n\nJSON API specification includes resources that are not necessarily a part of the original models.\nJsonApiX provides a way to retrieve the `links` and `meta` values from the JSON API input, without including those fields in your model.\n\nTo achieve this, your model need to extend `JsonApiModel` abstract class.\n\n\n```kotlin\n@Serializable\n@JsonApiX(\"person\")\ndata class Person(\n    val name: String?,\n    val surname: String,\n    val age: Int,\n    @HasOne(\"dog\")\n    val myFavoriteDog: Dog? = null\n) : JsonApiModel()\n```\n\n`JsonApiModel` is an abstract class that provides getters and setters for id and type.\n\nThe generated `PersonModel` and `PersonList` classes come with default meta and links, but we've provided options for customization. This allows you to tailor these elements to fit your specific project needs, enhancing flexibility and control.\n\n### Links\n\nLinks can be included in the root object, relationships objects and resource objects (`data` key). \nBy default, they have the following implementation:\n\n```kotlin\nclass DefaultLinks(\n    val self: String? = null,\n    val related: String? = null,\n    val first: String? = null,\n    val last: String? = null,\n    val next: String? = null,\n    val prev: String? = null\n) : Links\n```\n\nAnd the can be retrieved in the following way:\n\n```kotlin\n// Get root level links\npersonModel.rootLinks\n\n// Get relationships links\npersonModel.relationshipsLinks\n\n// Get resource object links\npersonModel.resourceObjectLinks\n```\n\n##### Custom links\n\nDevelopers can define their own custom link models to adapt to the specific requirements.\n\nLet's take this custom person links model as an example. \nEvery custom links model must extend the `Links` interface and have a `JsonApiXLinks` annotation. \n\n```kotlin\n@Serializable\n@JsonApiXLinks(type = \"person\", placementStrategy = LinksPlacementStrategy.ROOT)\ndata class PersonLinks(\n    val bioLink: String,\n    val socialLink: String\n) : Links\n```\n\n`LinksPlacementStartegy` enum is used to determine which links from the whole JSON API object will be replaced by a custom model.\nIt currently supports `ROOT`, `RELATIONSHIPS` and `DATA` links.\n\n\n### Meta\n\nIn JSON API specification, Meta is an optional, free-format key-value pair. It doesn't have a predefined default model.\nFor that reason, in order to use the meta feature, developer must define a custom meta model for each class, where he wants to use it. \n\nLet's take this `PersonMeta` model as an example.\nEvery custom meta model must extend the `Meta` interface and have a `JsonApiXMeta` annotation.\n\n```kotlin\n@Serializable\n@JsonApiXMeta(type = \"person\")\ndata class PersonMeta(val owner: String) : Meta\n```\n\nIn this example, the annotation processor will automatically make the meta type of a `PersonModel` class to be `PersonMeta`.\nDeveloper needs to make sure that the `type` parameter value in `JsonApiXMeta` matches the one in the `JsonApiX` above the original model.\nTo retrieve a meta object, a generic variant of the `meta()` method is used.\n\n```kotlin\n// Gets meta object\nperson.rootMeta\nperson.relationshipsMeta\nperson.resourceObjectMeta\n\n```\n\n## Retrofit Support\n\nTo enable Retrofit support, you need to add our custom converter in your retrofit builder. It takes an instance of `TypeAdapterFactory` as a\nparameter. No additional steps needed.\n\n```kotlin\nRetrofit.Builder()\n    .addConverterFactory(JsonXConverterFactory(TypeAdapterFactory()))\n    .baseUrl(\"https://www.example.com\")\n    .build()\n```\n\n## List of libraries used in the project\n\nThis chapter lists all the libraries that make a bigger contribution to the project. It is essential for any future\ncontributor to get\nfamiliar with them, before starting any work on the project. For that reason, links to the documentation are a part of\nthe list.\n\n- Kotlinx\n  serialization - [kotlinx.serialization/serialization-guide.md](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serialization-guide.md)\n- Kotlin poet - https://square.github.io/kotlinpoet/\n\nAlong with the libraries documentation, the developer should also know his way around the JSON API, so here is a link to\nthe [specification](https://jsonapi.org/).\n\n## Contributing\n\nWe believe that the community can help us improve and build better a product.\nPlease refer to our [contributing guide](CONTRIBUTING.md) to learn about the types of contributions we accept and the\nprocess for submitting them.\n\nTo ensure that our community remains respectful and professional, we defined\na [code of conduct](CODE_OF_CONDUCT.md) \u003c!-- and [coding standards](\u003clink\u003e) --\u003e that we expect all contributors to\nfollow.\n\nWe appreciate your interest and look forward to your contributions.\n\n## License\n\n```text\nCopyright 2024 Infinum\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n\n## Credits\n\nMaintained and sponsored by [Infinum](https://infinum.com).\n\n\u003cdiv align=\"center\"\u003e\n    \u003ca href='https://infinum.com'\u003e\n    \u003cpicture\u003e\n        \u003csource srcset=\"https://assets.infinum.com/brand/logo/static/white.svg\" media=\"(prefers-color-scheme: dark)\"\u003e\n        \u003cimg src=\"https://assets.infinum.com/brand/logo/static/default.svg\"\u003e\n    \u003c/picture\u003e\n    \u003c/a\u003e\n\u003c/div\u003e\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finfinum%2Fkotlin-jsonapix","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finfinum%2Fkotlin-jsonapix","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finfinum%2Fkotlin-jsonapix/lists"}