Intelligently set the targetObject by exploring the mapping graph in appropriateObjectRequestOperationWithObject: to better support cases in which you POST/PUT one object, but map back another. fixes #1081

This commit is contained in:
Blake Watters
2012-12-23 00:26:33 -05:00
parent 0a033596da
commit bc719087ac
2 changed files with 51 additions and 1 deletions

View File

@@ -169,6 +169,34 @@ static BOOL RKDoesArrayOfResponseDescriptorsContainEntityMapping(NSArray *respon
return NO;
}
static BOOL RKDoesArrayOfResponseDescriptorsContainMappingForClass(NSArray *responseDescriptors, Class classToBeMapped)
{
// Visit all mappings accessible from the object graphs of all response descriptors
NSMutableSet *accessibleMappings = [NSMutableSet set];
for (RKResponseDescriptor *responseDescriptor in responseDescriptors) {
if (! [accessibleMappings containsObject:responseDescriptor.mapping]) {
RKMappingGraphVisitor *graphVisitor = [[RKMappingGraphVisitor alloc] initWithMapping:responseDescriptor.mapping];
[accessibleMappings unionSet:graphVisitor.mappings];
}
}
// Enumerate all mappings and search for a mapping matching the class
for (RKMapping *mapping in accessibleMappings) {
if ([mapping isKindOfClass:[RKObjectMapping class]]) {
if ([[(RKObjectMapping *)mapping objectClass] isSubclassOfClass:classToBeMapped]) return YES;
}
if ([mapping isKindOfClass:[RKDynamicMapping class]]) {
RKDynamicMapping *dynamicMapping = (RKDynamicMapping *)mapping;
for (RKObjectMapping *mapping in dynamicMapping.objectMappings) {
if ([[(RKObjectMapping *)mapping objectClass] isSubclassOfClass:classToBeMapped]) return YES;
}
}
}
return NO;
}
static NSString *RKMIMETypeFromAFHTTPClientParameterEncoding(AFHTTPClientParameterEncoding encoding)
{
switch (encoding) {
@@ -419,7 +447,7 @@ static NSString *RKMIMETypeFromAFHTTPClientParameterEncoding(AFHTTPClientParamet
operation = [self objectRequestOperationWithRequest:request success:nil failure:nil];
}
operation.targetObject = object;
if (RKDoesArrayOfResponseDescriptorsContainMappingForClass(self.responseDescriptors, [object class])) operation.targetObject = object;
return operation;
}

View File

@@ -574,6 +574,28 @@
expect([manager.baseURL absoluteString]).to.equal(@"http://google.com/");
}
- (void)testPostingOneObjectAndGettingResponseMatchingAnotherClass
{
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[RKTestFactory baseURL]];
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestUser class]];
[userMapping addAttributeMappingsFromDictionary:@{ @"fullname": @"name" }];
RKObjectMapping *metaMapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]];
[metaMapping addAttributeMappingsFromArray:@[ @"status", @"version" ]];
RKResponseDescriptor *metaResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:metaMapping pathPattern:nil keyPath:@"meta" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[manager addResponseDescriptorsFromArray:@[ metaResponseDescriptor ]];
RKTestUser *user = [RKTestUser new];
RKObjectRequestOperation *requestOperation = [manager appropriateObjectRequestOperationWithObject:user method:RKRequestMethodPOST path:@"/ComplexUser" parameters:nil];
[requestOperation start];
[requestOperation waitUntilFinished];
expect(requestOperation.error).to.beNil();
expect(requestOperation.mappingResult).notTo.beNil();
expect([requestOperation.mappingResult array]).to.haveCountOf(1);
NSDictionary *expectedObject = @{ @"status": @"ok", @"version": @"0.3" };
expect([requestOperation.mappingResult firstObject]).to.equal(expectedObject);
}
- (void)testPostingOneObjectAndGettingResponseMatchingMultipleDescriptors
{
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[RKTestFactory baseURL]];