{"id":13498308,"url":"https://github.com/jasminb/jsonapi-converter","last_synced_at":"2026-01-06T12:59:48.231Z","repository":{"id":5463283,"uuid":"52023675","full_name":"jasminb/jsonapi-converter","owner":"jasminb","description":"JSONAPI-Converter is a Java/Android library that provides support for working with JSONAPI spec","archived":false,"fork":false,"pushed_at":"2024-07-31T21:12:18.000Z","size":383,"stargazers_count":273,"open_issues_count":60,"forks_count":81,"subscribers_count":20,"default_branch":"develop","last_synced_at":"2024-10-31T15:38:43.610Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","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/jasminb.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":"2016-02-18T17:03:38.000Z","updated_at":"2024-07-31T21:12:21.000Z","dependencies_parsed_at":"2024-01-18T23:04:46.611Z","dependency_job_id":"d886442f-96db-4212-86cd-a04532ca2cf6","html_url":"https://github.com/jasminb/jsonapi-converter","commit_stats":{"total_commits":161,"total_committers":26,"mean_commits":"6.1923076923076925","dds":0.2857142857142857,"last_synced_commit":"9fc31ecd5fdf2451956a537419c8a9255d198aef"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasminb%2Fjsonapi-converter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasminb%2Fjsonapi-converter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasminb%2Fjsonapi-converter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasminb%2Fjsonapi-converter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jasminb","download_url":"https://codeload.github.com/jasminb/jsonapi-converter/tar.gz/refs/heads/develop","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":[],"created_at":"2024-07-31T21:00:21.790Z","updated_at":"2026-01-06T12:59:48.222Z","avatar_url":"https://github.com/jasminb.png","language":"Java","funding_links":["https://paypal.me/jbegic"],"categories":["Uncategorized"],"sub_categories":["Uncategorized"],"readme":"### jsonapi-converter\n\n[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://paypal.me/jbegic)\n\nJSONAPI-Converter is a library that provides means for integrating with services using JSON API specification.\n\nFor information on JSON API specification please see: http://jsonapi.org/format/\n\nBesides providing support for request/response parsing, library provides a retrofit plugin.\n\nLibrary is using Jackson (https://github.com/FasterXML/jackson-databind) for JSON data parsing.\n\n#### Including the library in your project\n\nMaven:\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.github.jasminb\u003c/groupId\u003e\n  \u003cartifactId\u003ejsonapi-converter\u003c/artifactId\u003e\n  \u003cversion\u003e0.15\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nGradle:\n```groovy\nimplementation 'com.github.jasminb:jsonapi-converter:0.15'\n```\n\nSBT:\n\n```groovy\nlibraryDependencies += \"com.github.jasminb\" % \"jsonapi-converter\" % \"0.15\"\n```\n\nIn case you want to use current `SNAPSHOT` version of the project, make sure to add sonatype repository to your pom:\n\n```xml\n\u003crepositories\u003e\n    \u003crepository\u003e\n        \u003cid\u003eoss-sonatype\u003c/id\u003e\n        \u003cname\u003eoss-sonatype\u003c/name\u003e\n        \u003curl\u003ehttps://oss.sonatype.org/content/repositories/snapshots/\u003c/url\u003e\n        \u003csnapshots\u003e\n            \u003cenabled\u003etrue\u003c/enabled\u003e\n        \u003c/snapshots\u003e\n    \u003c/repository\u003e\n\u003c/repositories\u003e\n```\n\nThan to add dependency:\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.github.jasminb\u003c/groupId\u003e\n  \u003cartifactId\u003ejsonapi-converter\u003c/artifactId\u003e\n  \u003cversion\u003e0.16-SNAPSHOT\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n#### Important retrofit note\n\nRetrofit is used as scoped dependency (`provided`) which means that if one needs retrofit capabilities, retrofit needs\nto be included as a separate explicit dependency (it won't be pulled transitively).\n\n\n#### Writing your model classes\n\nWhen writing models that will be used to represent requests and responses, one needs to pay attention to following:\n\n - Each model class must be annotated with `com.github.jasminb.jsonapi.annotations.Type` annotation\n - Each class must contain an `String` attribute annotated with `com.github.jasminb.jsonapi.annotations.Id` annotation\n - All relationships must be annotated with `com.github.jasminb.jsonapi.annotations.Relationship` annotation\n - Attributes in the API that are _not_ well-formed Java identifiers, must use `JsonProperty` annotation\n\n#### Type annotation\n\nType annotation is used to instruct the serialisation/deserialisation library on how to process the given model class.\nAnnotation has single property `value` which is required and it should be set to whatever is the designated JSON API SPEC name for that type.\n\nExample:\n\n```java\n@Type(\"book\")\npublic class Book {\n ...\n}\n```\n\nNote that `@Type` annotation is not inherited from supperclasses.\n\n#### Id annotation\n\nId annotation is used to flag an attribute of a class as an `id` attribute. Each resource class must have an id field.\n\nIn case field annotated by the `@Id` annotation is not a `String` field, `@Id` annotation needs to be configured with proper `ResourceIdHandler`. \nLibrary provides handlers for `Long` and `Integer` types, in case types other than those mentioned are used, user must implement and provide proper id handler.\n\nId is a special attribute that is, together with type, used to uniquely identify a resource.\n\nId annotation is inheritable, one can define a base model class that contains a field with `@Id` annotation and then extend it to create a new type.\n\nExample:\n\n```java\n@Type(\"book\")\npublic class Book {\n  \n  @Id\n  private String isbn;\n  ...\n}\n```\n\nExample with inheritance:\n\n```java\npublic class BaseModel {\n  @Id\n  private String id;\n}\n\n@Type(\"book\")\npublic class Book extends BaseModel {\n  # Your custom member variables\n}\n```\n\nExample using `Long` as id\n\n```java\n@Type(\"book\")\npublic class Book {\n  \n  @Id(LongIdHandler.class)\n  private Long id;\n  ...\n}\n\n\n```\n\n#### LocalId annotation\n\nThis annotation is used to mark a class attribute as a holder of the `local identifier`.\nLocal identifiers may be used in cases where requests are originating on the client side. This annotation is optional\nand behaves in a similar way to the `@Id` annotation. It must be represented as a string in serialized form\nwhich means that for non-string class attributes, handler must be registered to convert from and to string type on\nserialization/deserialization.\n\nExample:\n\n```java\n@Type(\"book\")\npublic class Book {\n  \n  @Id\n  private String isbn;\n  @LocalId\n  private String localId;\n}\n```\n\nBy default, library will not serialize local id attribute, its serialization needs to be enabled explicitly:\n\n```java\nSerializationSettings settings = new SerializationSettings.Builder()\n\t\t\t\t.serializeLocalId(true)\n\t\t\t\t.build();\n\n// Using the settings on serialization call\nconverter.writeDocument(document, settings);\n\n```\n\nIt can also be enabled globally using the `SerializationFeature` options:\n\n```java\nconverter.enableSerializationOption(SerializationFeature.INCLUDE_LOCAL_ID);\n```\n\nFor deserialization, `lid` attribute is optional by default, it can be made required by `DeserializationFeature`\nmechanism:\n\n```java\nconverter.enableDeserializationOption(DeserializationFeature.REQUIRE_LOCAL_RESOURCE_ID);\n```\n\nSetting the option above means that deserialization will throw in case resource does not contain non-empty `lid` attribute.\n\n###### Important note\n\nBy default `REQUIRE_RESOURCE_ID` deserialization feature is enabled, which means that for server-side usage,\nwhere users want to use the `lid` mechanism, this option should be disabled:\n\n```java\nconverter.disableDeserializationOption(DeserializationFeature.REQUIRE_RESOURCE_ID);\n```\n\n#### Relationship annotation\n\nRelationship annotation is used to designate other resource types as a relationships.\n\nImagine modeling a simple library application, you would end up having a `Book` resource and another logical resource would be `Author`.\n\nYou can model this as two different classes where `Book` resource would have a relationship to an `Author`:\n\n```java\n@Type(\"book\")\npublic class Book {\n  @Id\n  private String isbn;\n  private String title;\n  \n  @Relationship(\"author\")\n  private Author author;\n}\n```\n\nRelationship annotation has following attributes:\n\n - value\n - resolve\n - serialise\n - relType\n \nValue attribute is required and each relationship must have it set (value attribute represents the 'name' of the relationship).\n\nResolve attribute is used to instruct the library on how to handle server responses where resource relationships are not provided in `included` section but are rather returned as `type` and `id` combination.\n\nLibrary has a support for registering global and typed relationship resolves which are used to resolve unresolved relationships.\nResolving a relationship means using provided `links` attribute to perform additional `HTTP` request and get the related object using the link provided.\n\nRelationship resolver interface has a single method:\n\n```java\nbyte [] resolve(String relationshipURL);\n````\n\nAfter implementing relationship resolver, in order to use it, one must register it with the instance of the `ResourceConverter`.\n\nExample:\n\n```java\nResourceConverter converter = new ResourceConverter(Book.class, Author.class);\nconverter.setGlobalResolver(new CustomRelationshipResolverInstance());\n```\n\nBesides support for global resolvers, there is an option to have different resolvers for different resource types:\n\n```java\nResourceConverter converter = new ResourceConverter(Book.class, Author.class);\nconverter.setTypeResolver(new CustomBooksResolver(), Book.class);\nconverter.setTypeResolver(new CustomAuthorResolver(), Author.class);\n\n```\n\nSerialise attribute is used to instruct the serialisar whether to include or exclude given relationship when serialising resources.\nI is enabled by default, if disabled relationship will not be serialised.\n\nRelationship type (`relType`) is used to instruct the library on how to resolve link data from raw server responses in order to\nresolve given relationship.\n\nThere two different relationship types:\n\n - `SELF` (`self` link will be followed to resolve relationship\n - `RELATED` (`related` link will be followed)\n \nHave in mind that relationship (same as id) is inheritable and can be defined in a base class.\n\n#### Polymorphic Relationships\n\nIn order to support polymorphic relationships, an `interface` needs to be created and than implemented by all possible types relationship supports. Created interface is used as a relationship's type (see example below).\n\n\nExample response containing multiple types in a relationship:\n\n```json\n{\n  \"data\": {\n    \"type\": \"dealerships\",\n    \"id\": \"1\",\n    \"attributes\": {\n      \"name\": \"Dealership name\"\n    },\n    \"links\": {\n      \"self\": \"http://example.com/dealerships/1\"\n    },\n    \"relationships\": {\n      \"inventory\": {\n        \"links\": {\n          \"self\": \"http://example.com/dealerships/1/relationships/inventory\",\n          \"related\": \"http://example.com/dealerships/1/inventory\"\n        },\n        \"data\": [\n          { \"type\": \"cars\", \"id\": \"2\" },\n          { \"type\": \"trucks\", \"id\": \"1\" }\n        ]\n      }\n    }\n  },\n  \"included\": [{\n    \"type\": \"cars\",\n    \"id\": \"2\",\n    \"attributes\": {\n      \"make\": \"BMW\",\n      \"model\": \"i8 Roadster\"\n    },\n    \"links\": {\n      \"self\": \"http://example.com/cars/2\"\n    }\n  }, {\n    \"type\": \"trucks\",\n    \"id\": \"1\",\n    \"attributes\": {\n      \"make\": \"Ford\",\n      \"model\": \"Semi\"\n    },\n    \"links\": {\n      \"self\": \"http://example.com/trucks/1\"\n    }\n  }]\n}\n```\n\nNeeded classes, and example usage:\n\n```java\npublic interface Driveable {}\n\n@Type(\"cars\")\npublic class Car implements Driveable {\n\t@Id\n\tprivate String id;\n\tprivate String model;\n\tprivate String make;\n\t// Getters and setters...\n}\n\n@Type(\"trucks\")\npublic class Truck implements Driveable {\n\n\t@Id\n\tprivate String id;\n\tprivate String make;\n\tprivate String model;\n        // Getters and setters...\n}\n\n@Type(\"dealerships\")\npublic class Dealership {\n\t@Id\n\tprivate String id;\n\tprivate String name;\n\tprivate String city;\n\n        // Interface is used as relalationship type (instead of concrete resource type)\n\t@Relationship(\"inventory\")\n\tprivate Collection\u003cDriveable\u003e automobiles;\n}\n\n// Putting everything together\nResourceConverter converter = new ResourceConverter(\"https://api.example.com\", Car.class, Dealership.class, Truck.class);\nJSONAPIDocument\u003cDealership\u003e document = converter.readDocument(apiResponse, Dealership.class);\n\n\n```\n\n#### Relationship meta and links\n\njsonapi-spec allows for having relationship-level metadata and links.\n\nIn order to gain access to returned relationship meta and links or ability to serialize it, use following annotations:\n - `RelationshipMeta`\n - `RelationshipLinks`\n \n Here is a version of the `Book` class with relationship meta/links added:\n \n ```java\n@Type(\"book\")\npublic class Book {\n  @Id\n  private String isbn;\n  private String title;\n  \n  @Relationship(\"author\")\n  private Author author;\n  \n  @RelationshipMeta(\"author\")\n  private Meta authorMeta\n  \n  @RelationshipLinks(\"author\")\n  private Links authorLinks\n}\n```\n\nMake sure not to confuse relationship meta and links with regular meta-data and link data explained below.\n\n#### Meta annotation\n\nBy JSON API specification, each resource can hold `meta` attribute. Meta can be arbitrary object that is defined by the API implementation.\n\nIn order to map and make meta available trough resource conversion, one must create a model that coresponds to the meta object returned by the API, create a member variable in the resource class using created model and annotate it using the `@Meta` annotation.\n\nMeta example:\n\n```java\n# Meta model class\n\npublic class MyCustomMetaClass {\n    private String myAttribute;\n    \n    public String getMyAttribute() {\n    \treturn myAttribute;\n    }\n    \n    public void setMyAttribute(String value) {\n    \tthis.myAttribute = value;\n    }\n}\n\n# Resource class with meta attribute\n\n@Type(\"book\")\npublic class Book {\n  @Id\n  private String isbn;\n  private String title;\n  \n  @Relationship(\"author\")\n  private Author author;\n  \n  @Meta\n  private MyCustomMetaClass meta;\n}\n\n```\n\nMeta annotation/attriubutes are inheritable.\n\n#### Links annotation\n\nJSON API specification allows for `links` to be part of resources. Links usually cary information about the resource itself (eg. its URI on the server).\n\nLiks are not arbitray objects, JSON API spec provides links structure therefore it is not required to create a new model to make links object available.\n\nLibrary provides a `com.github.jasminb.jsonapi.Links` class that must be used in order to make links data available in resources.\n\nExample:\n\n```java\n@Type(\"book\")\npublic class Book {\n  @Id\n  private String isbn;\n  private String title;\n  \n  @Relationship(\"author\")\n  private Author author;\n  \n  @Meta\n  private MyCustomMetaClass meta;\n  \n  @Links\n  private com.github.jasminb.jsonapi.Links links;\n}\n```\n\nLinks are inheritable.\n\n#### Attribute annotations\n\nIf your JSON API endpoint returns attributes that do not map well to Java identifiers, you'll get a fatal error on deserialization. The log message will tell you\nabout an unrecognized field with that name. To fix it, you can use `com.fasterxml.jackson.annotation.JsonProperty`.\n\nExample: your JSON API endpoint returns something like this\n\n```json\n{\n    \"data\": [\n        {\n            \"id\": \"1\",\n            \"type\": \"gears\",\n            \"attributes\": {\n                \"tooth-count\": 13,\n                \"tooth-depth\": 21\n            }\n        }\n    ]\n}\n```\n\nthen your model must be:\n\n```java\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\n@Type(\"gears\")\npublic class Gear {\n  @Id\n  private String id;\n\n  @JsonProperty(\"tooth-count\")\n  private Long toothCount;\n  @JsonProperty(\"tooth-depth\")\n  private Long toothDepth;\n}\n```\n\nThis also lets you use different names for your fields than your API.\n\n#### Full example\n\nDefine simple POJO, please pay attention to the added annotations:\n\n```java\n# Meta is optional, one does not have to define or use it\npublic class Meta {\n    private String myAttribute;\n    \n    public String getMyAttribute() {\n    \treturn myAttribute;\n    }\n    \n    public void setMyAttribute(String value) {\n    \tthis.myAttribute = value;\n    }\n}\n\n# Creating base class is optional but allows for writing more compact model classes\npublic class BaseResource {\n    @Id\n    private String id;\n    \n    @Meta\n    private Meta meta;\n    \n    @Links\n    private Links links;\n}\n\n@Type(\"book\")\npublic class Book extends BaseResource {\n  private String title;\n  \n  @Relationship(\"author\")\n  private Author author;\n  \n  @RelationshipMeta(\"author\")\n  private Meta authorMeta\n  \n  @RelationshipLinks(\"author\")\n  private Links authorLinks\n  \n  # getters and setters\n}\n\n@Type(\"author\")\npublic class Author extends BaseResource {\n  private String name;\n  \n  @Relationship(\"books\")\n  private List\u003cBook\u003e books;\n  \n  # getters and setters\n}\n```\n\nCreate a converter instance:\n\n```java\nResourceConverter converter = new ResourceConverter(Book.class, Author.class);\n\n// Get response data\nbyte [] rawResponse = ...get data from the wire\n\n// To convert raw data into single POJO\nJSONAPIDocument\u003cBook\u003e bookDocument = converter.readDocument(rawResponse, Book.class);\nBook book = bookDocument.get();\n\n// To convert raw data into collection\nJSONAPIDocument\u003cList\u003cBook\u003e\u003e bookDocumentCollection = converter.readDocumentCollection(rawResponse, Book.class);\nList\u003cBook\u003e bookCollection = bookDocumentCollection.get();\n\n```\n\nNote that calling `readDocument(...)` or `readDocumentCollection(...)` using content that contains `errors` (`{\"errors\" : [{...}]}`) attribute will produce `ResourceParseException`.\n\nThrown exception has a method (`getErrorResponse()`) that returns parsed `errors` content. Errors content is expected to comply to JSON API Spec.\n\n#### Top level links and meta\n\nBesides having links and meta information on resource level, by JSON API spec it is also possible to have meta, links or both as top level objects in server responses.\n\nTo gain access to top level meta/links, this library provides convenience methods available in `JSONAPIDocument`, namely:\n \n - `getMeta()`\n - `getLinks()`\n \n#### Resource serialization\n\nBesides providing options to deserialize json-api spec complaint resource representation, library also includes support for serializing resources.\n\nFollowing are available serialization options that can be enabled/disabled on `ResourceConverter` instance:\n\n - `INCLUDE_META` enabled by default, if enabled, meta data will be serialized\n - `INCLUDE_LINKS` enabled by default, if enabled links will be serialized\n - `INCLUDE_RELATIONSHIP_ATTRIBUTES` disabled by default, if enabled, relationship objects will be serialized fully, this means that besides generating `relationship` objects for each relationship, `included` section will be created that contains actual relationship attributes\n\nTo enable or disable serialization options:\n\n```java\nResourceConverter converter = ...\n# Enable generating included section\nconverter.enableSerializationOption(SerializationFeature.INCLUDE_RELATIONSHIP_ATTRIBUTES);\n\n# Disable generating included section\nconverter.disableSerializationOption(SerializationFeature.INCLUDE_RELATIONSHIP_ATTRIBUTES);\n\n```\n\n\nExample with `INCLUDE_RELATIONSHIP_ATTRIBUTES` disabled:\n\n```json\n{\n  \"data\": {\n    \"type\": \"articles\",\n    \"id\": \"id\",\n    \"attributes\": {\n      \"title\": \"title\"\n    },\n    \"relationships\": {\n      \"author\": {\n        \"data\": {\n          \"type\": \"people\",\n          \"id\": \"id\"\n        }\n      }\n    }\n  }\n}\n```\n\nExample with `INCLUDE_RELATIONSHIP_ATTRIBUTES` enabled:\n\n```json\n{\n  \"data\": {\n    \"type\": \"articles\",\n    \"id\": \"id\",\n    \"attributes\": {\n      \"title\": \"title\"\n    },\n    \"relationships\": {\n      \"author\": {\n        \"data\": {\n          \"type\": \"people\",\n          \"id\": \"id\"\n        }\n      }\n    }\n  },\n  \"included\": [\n    {\n      \"type\": \"people\",\n      \"id\": \"id\",\n      \"attributes\": {\n        \"firstName\": \"John\"\n      }\n    }\n  ]\n}\n```\n\n#### Example usage with retrofit\n\nAs a first step, define your model classes and annotate them using annotations described above.\n\nAfter defining models, define your service interfaces as you would usually do with 'standard' JSON/XML APIs.\n\nTo create retrofit instance:\n\n```java\n// Create object mapper\nObjectMapper objectMapper = new ObjectMapper();\n\n// Set serialisation/deserialisation options if needed (property naming strategy, etc...)\n\nRetrofit retrofit = new Retrofit.Builder()\n\t\t.baseUrl(\"https://yourapi\")\n\t\t.addConverterFactory(new JSONAPIConverterFactory(objectMapper, Book.class, Author.class))\n\t\t.build();\n\t\t\n// Create service using service interface\n\nMyBooksService booksService = retrofit.create(MyBooksService.class);\n\n```\n\n###### Synchronous usage\n\n```java\nResponse\u003cJSONAPIDocument\u003cBook\u003e\u003e bookResponse = booksService.find(\"123\").execute();\n\nif (bookResponse.isSuccess()) {\n    // Consume response\n} else {\n    ErrorResponse errorResponse = ErrorUtils.parseErrorResponse(bookResponse.errorBody());\n    // Handle error\n}\n```\n\n###### Asynchronous usage\n\n```java\nCall\u003cJSONAPIDocument\u003cBook\u003e\u003e bookServiceCall = service.getExampleResource();\n\nbookServiceCall.enqueue(new Callback\u003cBook\u003e() {\n  @Override\n  public void onResponse(Response\u003cJSONAPIDocument\u003cBook\u003e\u003e bookResponse, Retrofit retrofit) {\n    if (bookResponse.isSuccess()) {\n        // Consume response\n    } else {\n        ErrorResponse errorResponse = ErrorUtils.parseErrorResponse(bookResponse.errorBody());\n        // Handle error\n    }\n  }\n  \n  @Override\n  public void onFailure(Throwable throwable) {\n    // Handle network errors/unexpected errors\n  }\n});\n```\n\nNotice that expected return types in `MyBookService` calls are all wrapped with `JSONAPIDocument`, this is intended way to use the library since it allows for gaining access to response level `meta` and `links` data.\n\nExample service interface:\n\n```java\npublic interface MyBooksService {\n    @GET(\"books\")\n    Call\u003cJSONAPIDocument\u003cList\u003cBook\u003e\u003e allBooks();\n}\n\n```\n\n#### Tips\n\nIf you need a `String` as an output when serializing objects, you can do the following:\n\n\n```java\nbyte [] serializedObject = resourceConverter.writeObject(...);\nString serializedAsString = new String(serializedObject);\n```\n\n#### Note for kotlin users\n\nHave in mind that using `open` classes as type parameters in relationship collections will not work, for instance:\n\n```java\n@Type(\"base\")\nopen class MyClass {\n\n    @Relationship(\"my-relationship\")\n    var bases: List\u003cMyClass\u003e? = null\n}\n```\n\nRemoving the `open` modifier will solve the issue.\n\n#### Note for Proguard\n\nThis library use reflection at runtime for checking if all registred types have an ID-field.  \nYou have to add this proguard rule:\n```\n# Keep jsonapi-converter relative fields\n-keepclassmembers class * {\n    @com.github.jasminb.jsonapi.annotations.Id \u003cfields\u003e;\n}\n```\n\nProguard should remove all fields and methods that you are not accessing. If you would like to keep all deserialized fields, you can add a rule for unconditionally keep all your POJO classes.\n```\n# Keep all POJO classes\n-keep class com.example.json.** {*;}\n```\nReplace `com.example.json` by the correct package.\n\n```\n# Keep custom id handlers\n-keep class * implements com.github.jasminb.jsonapi.ResourceIdHandler\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjasminb%2Fjsonapi-converter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjasminb%2Fjsonapi-converter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjasminb%2Fjsonapi-converter/lists"}