diff --git a/Code/Network/RKObjectManager.m b/Code/Network/RKObjectManager.m index 2322491c..82058e10 100644 --- a/Code/Network/RKObjectManager.m +++ b/Code/Network/RKObjectManager.m @@ -68,9 +68,14 @@ static NSArray *RKFilteredArrayOfResponseDescriptorsMatchingPath(NSArray *respon */ static RKRequestDescriptor *RKRequestDescriptorFromArrayMatchingObject(NSArray *requestDescriptors, id object) { - for (RKRequestDescriptor *requestDescriptor in requestDescriptors) { - if ([requestDescriptor matchesObject:object]) return requestDescriptor; - } + Class searchClass = [object class]; + do { + for (RKRequestDescriptor *requestDescriptor in requestDescriptors) { + if ([requestDescriptor.objectClass isEqual:searchClass]) return requestDescriptor; + } + searchClass = [searchClass superclass]; + } while (searchClass); + return nil; } @@ -459,7 +464,11 @@ static NSString *RKMIMETypeFromAFHTTPClientParameterEncoding(AFHTTPClientParamet - (void)addRequestDescriptor:(RKRequestDescriptor *)requestDescriptor { NSParameterAssert(requestDescriptor); + if ([self.requestDescriptors containsObject:requestDescriptor]) return; NSAssert([requestDescriptor isKindOfClass:[RKRequestDescriptor class]], @"Expected an object of type RKRequestDescriptor, got '%@'", [requestDescriptor class]); + [self.requestDescriptors enumerateObjectsUsingBlock:^(RKRequestDescriptor *registeredDescriptor, NSUInteger idx, BOOL *stop) { + NSAssert(![registeredDescriptor.objectClass isEqual:requestDescriptor.objectClass], @"Cannot add a request descriptor for the same object class as an existing request descriptor."); + }]; [self.mutableRequestDescriptors addObject:requestDescriptor]; } diff --git a/Tests/Logic/ObjectMapping/RKObjectManagerTest.m b/Tests/Logic/ObjectMapping/RKObjectManagerTest.m index 609da028..ba6d97c7 100644 --- a/Tests/Logic/ObjectMapping/RKObjectManagerTest.m +++ b/Tests/Logic/ObjectMapping/RKObjectManagerTest.m @@ -26,6 +26,12 @@ #import "RKCat.h" #import "RKObjectMapperTestModel.h" +@interface RKSubclassedTestModel : RKObjectMapperTestModel +@end + +@implementation RKSubclassedTestModel +@end + @interface RKTestAFHTTPClient : AFHTTPClient @end @@ -480,6 +486,48 @@ }); } +- (void)testThatAttemptingToAddARequestDescriptorThatOverlapsAnExistingEntryGeneratesAnError +{ + RKObjectMapping *mapping = [RKObjectMapping requestMapping]; + RKRequestDescriptor *requestDesriptor1 = [RKRequestDescriptor requestDescriptorWithMapping:mapping objectClass:[RKCat class] rootKeyPath:nil]; + RKRequestDescriptor *requestDesriptor2 = [RKRequestDescriptor requestDescriptorWithMapping:mapping objectClass:[RKCat class] rootKeyPath:@"cat"]; + RKObjectManager *objectManager = [RKTestFactory objectManager]; + [objectManager addRequestDescriptor:requestDesriptor1]; + + NSException *caughtException = nil; + @try { + [objectManager addRequestDescriptor:requestDesriptor2]; + } + @catch (NSException *exception) { + caughtException = exception; + } + @finally { + expect(caughtException).notTo.beNil(); + } +} + +- (void)testThatRegisteringARequestDescriptorForASubclassSecondWillMatchAppropriately +{ + RKObjectMapping *mapping1 = [RKObjectMapping requestMapping]; + [mapping1 addAttributeMappingsFromArray:@[ @"name" ]]; + RKObjectMapping *mapping2 = [RKObjectMapping requestMapping]; + [mapping2 addAttributeMappingsFromArray:@[ @"age" ]]; + + RKRequestDescriptor *requestDesriptor1 = [RKRequestDescriptor requestDescriptorWithMapping:mapping1 objectClass:[RKObjectMapperTestModel class] rootKeyPath:nil]; + RKRequestDescriptor *requestDesriptor2 = [RKRequestDescriptor requestDescriptorWithMapping:mapping2 objectClass:[RKSubclassedTestModel class] rootKeyPath:@"subclassed"]; + RKObjectManager *objectManager = [RKTestFactory objectManager]; + objectManager.requestSerializationMIMEType = RKMIMETypeJSON; + [objectManager addRequestDescriptor:requestDesriptor1]; + [objectManager addRequestDescriptor:requestDesriptor2]; + + RKSubclassedTestModel *model = [RKSubclassedTestModel new]; + model.name = @"Blake"; + model.age = @30; + NSURLRequest *request = [objectManager requestWithObject:model method:RKRequestMethodPOST path:@"/path" parameters:nil]; + NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:request.HTTPBody options:0 error:nil]; + expect(dictionary).to.equal(@{ @"subclassed": @{ @"age": @(30) } }); +} + //- (void)testShouldHandleConnectionFailures //{ // NSString *localBaseURL = [NSString stringWithFormat:@"http://127.0.0.1:3001"]; diff --git a/Tests/Models/RKObjectMapperTestModel.h b/Tests/Models/RKObjectMapperTestModel.h index f3f4595b..b3785653 100644 --- a/Tests/Models/RKObjectMapperTestModel.h +++ b/Tests/Models/RKObjectMapperTestModel.h @@ -21,11 +21,7 @@ #import -@interface RKObjectMapperTestModel : NSObject { - NSString *_name; - NSNumber *_age; - NSDate *_createdAt; -} +@interface RKObjectMapperTestModel : NSObject @property (nonatomic, strong) NSString *name; @property (nonatomic, strong) NSNumber *age; diff --git a/Tests/Models/RKObjectMapperTestModel.m b/Tests/Models/RKObjectMapperTestModel.m index 8029c569..8ee979fd 100644 --- a/Tests/Models/RKObjectMapperTestModel.m +++ b/Tests/Models/RKObjectMapperTestModel.m @@ -21,9 +21,4 @@ #import "RKObjectMapperTestModel.h" @implementation RKObjectMapperTestModel - -@synthesize name = _name; -@synthesize age = _age; -@synthesize createdAt = _createdAt; - @end