{"id":16699724,"url":"https://github.com/gonzalezreal/groot","last_synced_at":"2025-04-04T17:09:44.256Z","repository":{"id":18288342,"uuid":"21458428","full_name":"gonzalezreal/Groot","owner":"gonzalezreal","description":"From JSON to Core Data and back.","archived":false,"fork":false,"pushed_at":"2019-12-16T08:16:12.000Z","size":446,"stargazers_count":534,"open_issues_count":15,"forks_count":61,"subscribers_count":26,"default_branch":"master","last_synced_at":"2024-10-13T18:08:05.825Z","etag":null,"topics":["coredata","json","objective-c","serialization","swift"],"latest_commit_sha":null,"homepage":"","language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gonzalezreal.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-07-03T10:14:26.000Z","updated_at":"2024-06-23T15:17:10.000Z","dependencies_parsed_at":"2022-08-25T10:51:34.605Z","dependency_job_id":null,"html_url":"https://github.com/gonzalezreal/Groot","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gonzalezreal%2FGroot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gonzalezreal%2FGroot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gonzalezreal%2FGroot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gonzalezreal%2FGroot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gonzalezreal","download_url":"https://codeload.github.com/gonzalezreal/Groot/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247217221,"owners_count":20903009,"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":["coredata","json","objective-c","serialization","swift"],"created_at":"2024-10-12T18:08:02.185Z","updated_at":"2025-04-04T17:09:44.240Z","avatar_url":"https://github.com/gonzalezreal.png","language":"Objective-C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Groot\n[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n\nGroot provides a simple way of serializing Core Data object graphs from or into JSON.\n\nIt uses [annotations](Documentation/Annotations.md) in the Core Data model to perform the serialization and provides the following features:\n\n1. Attribute and relationship mapping to JSON key paths.\n2. Value transformation using named `NSValueTransformer` objects.\n3. Object graph preservation.\n4. Support for entity inheritance\n\n## Installing Groot\n\n##### Using CocoaPods\n\nAdd the following to your `Podfile`:\n\n``` ruby\nuse_frameworks!\npod 'Groot'\n```\n\nOr, if you need to support iOS 6 / OS X 10.8:\n\n``` ruby\npod 'Groot/ObjC'\n```\n\nThen run `$ pod install`.\n\nIf you don’t have CocoaPods installed or integrated into your project, you can learn how to do so [here](http://cocoapods.org).\n\n##### Using Carthage\n\nAdd the following to your `Cartfile`:\n\n```\ngithub \"gonzalezreal/Groot\"\n```\n\nThen run `$ carthage update`.\n\nFollow the instructions in [Carthage’s README](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application]) to add the framework to your project.\n\nYou may need to set **Embedded Content Contains Swift Code** to **YES** in the build settings for targets that only contain Objective-C code.\n\n## Getting started\n\nConsider the following JSON describing a well-known comic book character:\n\n```json\n{\n    \"id\": \"1699\",\n    \"name\": \"Batman\",\n    \"real_name\": \"Bruce Wayne\",\n    \"powers\": [\n        {\n            \"id\": \"4\",\n            \"name\": \"Agility\"\n        },\n        {\n            \"id\": \"9\",\n            \"name\": \"Insanely Rich\"\n        }\n    ],\n    \"publisher\": {\n        \"id\": \"10\",\n        \"name\": \"DC Comics\"\n    }\n}\n```\n\nWe could translate this into a Core Data model using three entities: `Character`, `Power` and `Publisher`.\n\n\u003cimg src=\"https://cloud.githubusercontent.com/assets/373190/6988401/5346423a-da51-11e4-8bf1-a41da3a7372f.png\" alt=\"Model\" width=600 height=334/\u003e\n\n\n### Mapping attributes and relationships\n\nGroot relies on the presence of certain key-value pairs in the user info dictionary associated with entities, attributes and relationships to serialize managed objects from or into JSON. These key-value pairs are often referred in the documentation as [annotations](Documentation/Annotations.md).\n\nIn our example, we should add a `JSONKeyPath` in the user info dictionary of each attribute and relationship specifying the corresponding key path in the JSON:\n\n* `id` for the `identifier` attribute,\n* `name` for the `name` attribute,\n* `real_name` for the `realName` attribute,\n* `powers` for the `powers` relationship,\n* `publisher` for the `publisher` relationship,\n* etc.\n\nAttributes and relationships that don't have a `JSONKeyPath` entry are **not considered** for JSON serialization or deserialization.\n\n### Value transformers\n\nWhen we created the model we decided to use `Integer 64` for our `identifier` attributes. The problem is that, for compatibility reasons, the JSON uses strings for `id` values.\n\nWe can add a `JSONTransformerName` entry to each `identifier` attribute's user info dictionary specifying the name of a value transformer that converts strings to numbers.\n\nGroot provides a simple way for creating and registering named value transformers:\n\n```swift\n// Swift\n\nfunc toString(_ value: Int) -\u003e String? {\n    return String(value)\n}\n\nfunc toInt(_ value: String) -\u003e Int? {\n    return Int(value)\n}\n\nValueTransformer.setValueTransformer(withName: \"StringToInteger\", transform: toInt, reverseTransform: toString)\n```\n\n```objc\n// Objective-C\n\n[NSValueTransformer grt_setValueTransformerWithName:@\"StringToInteger\" transformBlock:^id(NSString *value) {\n    return @([value integerValue]);\n} reverseTransformBlock:^id(NSNumber *value) {\n    return [value stringValue];\n}];\n```\n\n### Object graph preservation\n\nTo preserve the object graph and avoid duplicating information when serializing managed objects from JSON, Groot needs to know how to uniquely identify your model objects.\n\nIn our example, we should add an `identityAttributes` entry to the `Character`, `Power` and `Publisher` entities user dictionaries with the value `identifier`.\n\nAdding the `identityAttributes` annotation to your entities can affect performance when serializing from JSON. For more information see [Object Uniquing Performance](#object-uniquing-performance).\n\nFor more information about annotating your model have a look at [Annotations](Documentation/Annotations.md).\n\n### Serializing from JSON\n\nNow that we have our Core Data model ready we can start adding some data.\n\n```swift\n// Swift\n\nlet batmanJSON: JSONDictionary = [\n    \"name\": \"Batman\",\n    \"id\": \"1699\",\n    \"powers\": [\n        [\n            \"id\": \"4\",\n            \"name\": \"Agility\"\n        ],\n        [\n            \"id\": \"9\",\n            \"name\": \"Insanely Rich\"\n        ]\n    ],\n    \"publisher\": [\n        \"id\": \"10\",\n        \"name\": \"DC Comics\"\n    ]\n]\n\ndo {\n    let batman: Character = try object(fromJSONDictionary: batmanJSON, inContext: context)\n} catch let error as NSError {\n    // handle error\n}\n```\n\n```objc\n// Objective-C\n\nCharacter *batman = [GRTJSONSerialization objectWithEntityName:@\"Character\"\n                                            fromJSONDictionary:batmanJSON\n                                                     inContext:self.context\n                                                         error:\u0026error];\n```\n\nIf we want to update the object we just created, Groot can merge the changes for us:\n\n```swift\n// Swift\n\nlet updateJSON: JSONDictionary = [\n    \"id\": \"1699\",\n    \"real_name\": \"Bruce Wayne\",\n]\n\ndo {\n    // This will return the previously created managed object\n    let batman: Character = try object(fromJSONDictionary: updateJSON, inContext: context)\n} catch let error as NSError {\n    // handle error\n}\n```\n\n#### Serializing relationships from identifiers\n\nSuppose that our API does not return full objects for the relationships but only the identifiers.\n\nWe don't need to change our model to support this situation:\n\n```swift\n// Swift\n\nlet batmanJSON: JSONDictionary = [\n    \"name\": \"Batman\",\n    \"real_name\": \"Bruce Wayne\",\n    \"id\": \"1699\",\n    \"powers\": [\"4\", \"9\"],\n    \"publisher\": \"10\"\n]\n\ndo {\n    let batman: Character = try object(fromJSONDictionary: batmanJSON, inContext: context)\n} catch let error as NSError {\n    // handle error\n}\n```\n\nThe above code creates a full `Character` object and the corresponding relationships pointing to `Power` and `Publisher` objects that just have the identifier attribute populated.\n\nWe can import powers and publisher from different JSON objects and Groot will merge them nicely:\n\n```swift\n// Swift\n\nlet powersJSON: JSONArray = [\n    [\n        \"id\": \"4\",\n        \"name\": \"Agility\"\n    ],\n    [\n        \"id\": \"9\",\n        \"name\": \"Insanely Rich\"\n    ]\n]\n\nlet publisherJSON: JSONDictionary = [\n    \"id\": \"10\",\n    \"name\": \"DC Comics\"\n]\n\ndo {\n    let _: [Power] = try objects(fromJSONArray: powersJSON, inContext: context)\n    let _: Publisher = try object(fromJSONDictionary: publisherJSON, inContext: context)\n} catch let error as NSError {\n    // handle error\n}\n```\n\nNote that serializing relationships from identifiers only works with entities specifying **only one attribute** as the value of `identityAttributes` annotation.\n\nFor more serialization alternatives check [Groot.swift](Groot/Groot.swift) and [GRTJSONSerialization.h](Groot/GRTJSONSerialization.h).\n\n### Entity inheritance\n\nGroot supports entity inheritance via the [entityMapperName](Documentation/Annotations.md#entitymappername) annotation.\n\nIf you are using SQLite as your persistent store, Core Data implements entity inheritance by creating one table for the parent entity and all child entities, with a superset of all their attributes. This can obviously have unintended performance consequences if you have a lot of data in the entities, so use this feature wisely.\n\n### Object Uniquing Performance\n\n**Object uniquing** can affect performance when serialising from JSON, as it requires fetching data from the database before inserting.\n\nIf you take a look on how **Groot** is implemented, there are three serialization strategies:\n\n* Insert\n* Uniquing\n* Composite Uniquing\n\nAs you may guess, the first one is the most performant as it does not fetch from the database. If you know that there is no duplicate data in your data set, **DO NOT** set `identityAttributes` in your entity. This will make Groot use the *Insert* strategy.\n\nGroot will pick the *Uniquing* strategy if the `identityAttributes` annotation has a single attribute, otherwise it will pick the *Composite Uniquing* strategy.\n\nThe *Uniquing* strategy requires one fetch for every array of JSON objects, whereas the *Composite Uniquing* strategy requires one fetch for every single JSON object (it is potentially the slowest of the three strategies).\n\n### Serializing to JSON\n\nGroot provides methods to serialize managed objects back to JSON:\n\n```swift\n// Swift\n\nlet result = json(fromObject: batman)\n```\n\n```objc\n// Objective-C\n\nNSDictionary *JSONDictionary = [GRTJSONSerialization JSONDictionaryFromObject:batman];\n```\n\nFor more serialization alternatives check [Groot.swift](Groot/Groot.swift) and [GRTJSONSerialization.h](Groot/GRTJSONSerialization.h).\n\n## Contact\n\n[Guillermo Gonzalez](http://github.com/gonzalezreal)  \n[@gonzalezreal](https://twitter.com/gonzalezreal)\n\n## License\n\nGroot is available under the [MIT license](LICENSE.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgonzalezreal%2Fgroot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgonzalezreal%2Fgroot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgonzalezreal%2Fgroot/lists"}