FEMDeserializer.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. // For License please refer to LICENSE file in the root of FastEasyMapping project
  2. #import "FEMDeserializer.h"
  3. #import <CoreData/CoreData.h>
  4. #import "FEMTypeIntrospection.h"
  5. #import "NSArray+FEMPropertyRepresentation.h"
  6. #import "FEMObjectStore.h"
  7. #import "FEMRelationshipAssignmentContext+Internal.h"
  8. #import "FEMRepresentationUtility.h"
  9. #import "FEMManagedObjectStore.h"
  10. #import "NSObject+FEMKVCExtension.h"
  11. @implementation FEMDeserializer {
  12. struct {
  13. BOOL willMapObject: 1;
  14. BOOL didMapObject: 1;
  15. BOOL willMapCollection: 1;
  16. BOOL didMapCollection: 1;
  17. } _delegateFlags;
  18. }
  19. #pragma mark - Init
  20. - (id)initWithStore:(FEMObjectStore *)store {
  21. NSParameterAssert(store != nil);
  22. self = [super init];
  23. if (self) {
  24. _store = store;
  25. }
  26. return self;
  27. }
  28. - (nonnull instancetype)init {
  29. return [self initWithStore:[[FEMObjectStore alloc] init]];
  30. }
  31. - (nonnull instancetype)initWithContext:(NSManagedObjectContext *)context {
  32. return [self initWithStore:[[FEMManagedObjectStore alloc] initWithContext:context]];
  33. }
  34. #pragma mark - Delegate
  35. - (void)setDelegate:(id <FEMDeserializerDelegate>)delegate {
  36. _delegate = delegate;
  37. _delegateFlags.willMapObject = [_delegate respondsToSelector:@selector(deserializer:willMapObjectFromRepresentation:mapping:)];
  38. _delegateFlags.didMapObject = [_delegate respondsToSelector:@selector(deserializer:didMapObject:fromRepresentation:mapping:)];
  39. _delegateFlags.willMapCollection = [_delegate respondsToSelector:@selector(deserializer:willMapCollectionFromRepresentation:mapping:)];
  40. _delegateFlags.didMapCollection = [_delegate respondsToSelector:@selector(deserializer:didMapCollection:fromRepresentation:mapping:)];
  41. }
  42. #pragma mark - Deserialization
  43. - (void)fulfillObjectRelationships:(id)object fromRepresentation:(NSDictionary *)representation usingMapping:(FEMMapping *)mapping {
  44. for (FEMRelationship *relationship in mapping.relationships) {
  45. @autoreleasepool {
  46. id relationshipRepresentation = FEMRepresentationRootForKeyPath(representation, relationship.keyPath);
  47. if (relationshipRepresentation == nil) continue;
  48. id targetValue = nil;
  49. if (relationshipRepresentation != NSNull.null) {
  50. if (relationship.isToMany) {
  51. targetValue = [self _collectionFromRepresentation:relationshipRepresentation
  52. mapping:relationship.mapping
  53. allocateIfNeeded:!relationship.weak];
  54. objc_property_t property = class_getProperty([object class], [relationship.property UTF8String]);
  55. targetValue = [targetValue fem_propertyRepresentation:property];
  56. } else {
  57. targetValue = [self _objectFromRepresentation:relationshipRepresentation
  58. mapping:relationship.mapping
  59. allocateIfNeeded:!relationship.weak];
  60. }
  61. }
  62. FEMRelationshipAssignmentContext *context = [self.store newAssignmentContext];
  63. context.destinationObject = object;
  64. context.relationship = relationship;
  65. context.sourceRelationshipValue = [object valueForKey:relationship.property];
  66. context.targetRelationshipValue = targetValue;
  67. id assignmentValue = relationship.assignmentPolicy(context);
  68. [object setValue:assignmentValue forKey:relationship.property];
  69. }
  70. }
  71. }
  72. - (void)setAttributeValue:(FEMAttribute *)attribute onObject:(id)object fromRepresentation:(id)representation {
  73. id value = FEMRepresentationValueForAttribute(representation, attribute);
  74. if (value == NSNull.null) {
  75. if (!FEMObjectPropertyTypeIsScalar(object, attribute.property)) {
  76. [object setValue:nil forKey:attribute.property];
  77. }
  78. } else if (value) {
  79. [object fem_setValueIfDifferent:value forKey:attribute.property];
  80. }
  81. }
  82. - (id)_fillObject:(id)object fromRepresentation:(NSDictionary *)representation mapping:(FEMMapping *)mapping {
  83. for (FEMAttribute *attribute in mapping.attributes) {
  84. [self setAttributeValue:attribute onObject:object fromRepresentation:representation];
  85. }
  86. [self fulfillObjectRelationships:object fromRepresentation:representation usingMapping:mapping];
  87. return object;
  88. }
  89. - (id)_objectFromRepresentation:(NSDictionary *)representation mapping:(FEMMapping *)mapping allocateIfNeeded:(BOOL)allocate {
  90. id object = [self.store registeredObjectForRepresentation:representation mapping:mapping];
  91. if (!object && allocate) {
  92. object = [self.store newObjectForMapping:mapping];
  93. }
  94. if (!object) {
  95. return nil;
  96. }
  97. if (_delegateFlags.willMapObject) {
  98. [self.delegate deserializer:self willMapObjectFromRepresentation:representation mapping:mapping];
  99. }
  100. [self _fillObject:object fromRepresentation:representation mapping:mapping];
  101. if ([self.store canRegisterObject:object forMapping:mapping]) {
  102. [self.store registerObject:object forMapping:mapping];
  103. }
  104. if (_delegateFlags.didMapObject) {
  105. [self.delegate deserializer:self didMapObject:object fromRepresentation:representation mapping:mapping];
  106. }
  107. return object;
  108. }
  109. - (NSArray *)_collectionFromRepresentation:(NSArray *)representation mapping:(FEMMapping *)mapping allocateIfNeeded:(BOOL)allocate {
  110. if (_delegateFlags.willMapCollection) {
  111. [self.delegate deserializer:self willMapCollectionFromRepresentation:representation mapping:mapping];
  112. }
  113. NSMutableArray *output = [[NSMutableArray alloc] initWithCapacity:representation.count];
  114. for (id objectRepresentation in representation) {
  115. @autoreleasepool {
  116. id object = [self _objectFromRepresentation:objectRepresentation mapping:mapping allocateIfNeeded:allocate];
  117. [output addObject:object];
  118. }
  119. }
  120. if (_delegateFlags.didMapCollection) {
  121. [self.delegate deserializer:self didMapCollection:output fromRepresentation:representation mapping:mapping];
  122. }
  123. return output;
  124. }
  125. #pragma mark - Public
  126. - (id)objectFromRepresentation:(NSDictionary *)representation mapping:(FEMMapping *)mapping {
  127. [self.store prepareTransactionForMapping:mapping ofRepresentation:@[representation]];
  128. [self.store beginTransaction];
  129. id root = FEMRepresentationRootForKeyPath(representation, mapping.rootPath);
  130. id object = [self _objectFromRepresentation:root mapping:mapping allocateIfNeeded:YES];
  131. [self.store commitTransaction];
  132. return object;
  133. }
  134. - (id)fillObject:(id)object fromRepresentation:(NSDictionary *)representation mapping:(FEMMapping *)mapping {
  135. if (_delegateFlags.willMapObject) {
  136. [self.delegate deserializer:self willMapObjectFromRepresentation:representation mapping:mapping];
  137. }
  138. [self.store prepareTransactionForMapping:mapping ofRepresentation:@[representation]];
  139. [self.store beginTransaction];
  140. id root = FEMRepresentationRootForKeyPath(representation, mapping.rootPath);
  141. [self _fillObject:object fromRepresentation:root mapping:mapping];
  142. [self.store commitTransaction];
  143. if (_delegateFlags.didMapObject) {
  144. [self.delegate deserializer:self didMapObject:object fromRepresentation:representation mapping:mapping];
  145. }
  146. return object;
  147. }
  148. - (NSArray *)collectionFromRepresentation:(NSArray *)representation mapping:(FEMMapping *)mapping {
  149. [self.store prepareTransactionForMapping:mapping ofRepresentation:representation];
  150. [self.store beginTransaction];
  151. id root = FEMRepresentationRootForKeyPath(representation, mapping.rootPath);
  152. NSArray *objects = [self _collectionFromRepresentation:root mapping:mapping allocateIfNeeded:YES];
  153. [self.store commitTransaction];
  154. return objects;
  155. }
  156. @end
  157. @implementation FEMDeserializer (Extension)
  158. + (id)objectFromRepresentation:(NSDictionary *)representation mapping:(FEMMapping *)mapping context:(NSManagedObjectContext *)context {
  159. FEMManagedObjectStore *store = [[FEMManagedObjectStore alloc] initWithContext:context];
  160. FEMDeserializer *deserializer = [[FEMDeserializer alloc] initWithStore:store];
  161. return [deserializer objectFromRepresentation:representation mapping:mapping];
  162. }
  163. + (id)objectFromRepresentation:(NSDictionary *)representation mapping:(FEMMapping *)mapping {
  164. FEMObjectStore *store = [[FEMObjectStore alloc] init];
  165. FEMDeserializer *deserializer = [[FEMDeserializer alloc] initWithStore:store];
  166. return [deserializer objectFromRepresentation:representation mapping:mapping];
  167. }
  168. + (id)fillObject:(id)object fromRepresentation:(NSDictionary *)representation mapping:(FEMMapping *)mapping {
  169. FEMObjectStore *store = nil;
  170. if ([object isKindOfClass:NSManagedObject.class]) {
  171. store = [[FEMManagedObjectStore alloc] initWithContext:[(NSManagedObject *)object managedObjectContext]];
  172. } else {
  173. store = [[FEMObjectStore alloc] init];
  174. }
  175. FEMDeserializer *deserializer = [[FEMDeserializer alloc] initWithStore:store];
  176. return [deserializer fillObject:object fromRepresentation:representation mapping:mapping];
  177. };
  178. + (NSArray *)collectionFromRepresentation:(NSArray *)representation mapping:(FEMMapping *)mapping context:(NSManagedObjectContext *)context {
  179. FEMManagedObjectStore *store = [[FEMManagedObjectStore alloc] initWithContext:context];
  180. FEMDeserializer *deserializer = [[FEMDeserializer alloc] initWithStore:store];
  181. return [deserializer collectionFromRepresentation:representation mapping:mapping];
  182. }
  183. + (NSArray *)collectionFromRepresentation:(NSArray *)representation mapping:(FEMMapping *)mapping {
  184. FEMObjectStore *store = [[FEMObjectStore alloc] init];
  185. FEMDeserializer *deserializer = [[FEMDeserializer alloc] initWithStore:store];
  186. return [deserializer collectionFromRepresentation:representation mapping:mapping];
  187. }
  188. @end
  189. @implementation FEMDeserializer (FEMManagedObjectDeserializer_Deprecated)
  190. + (id)deserializeObjectExternalRepresentation:(NSDictionary *)externalRepresentation usingMapping:(FEMMapping *)mapping context:(NSManagedObjectContext *)context {
  191. return [self objectFromRepresentation:externalRepresentation mapping:mapping context:context];
  192. }
  193. + (NSArray *)deserializeCollectionExternalRepresentation:(NSArray *)externalRepresentation usingMapping:(FEMMapping *)mapping context:(NSManagedObjectContext *)context {
  194. return [self collectionFromRepresentation:externalRepresentation mapping:mapping context:context];
  195. }
  196. @end
  197. @implementation FEMDeserializer (FEMObjectDeserializer_Deprecated)
  198. + (id)deserializeObjectExternalRepresentation:(NSDictionary *)externalRepresentation usingMapping:(FEMMapping *)mapping {
  199. return [self objectFromRepresentation:externalRepresentation mapping:mapping];
  200. }
  201. + (id)fillObject:(NSManagedObject *)object fromExternalRepresentation:(NSDictionary *)externalRepresentation usingMapping:(FEMMapping *)mapping {
  202. return [self fillObject:object fromRepresentation:externalRepresentation mapping:mapping];
  203. }
  204. + (NSArray *)deserializeCollectionExternalRepresentation:(NSArray *)externalRepresentation usingMapping:(FEMMapping *)mapping {
  205. return [self collectionFromRepresentation:externalRepresentation mapping:mapping];
  206. }
  207. @end