Files
RestKit/Code/ObjectMapping/RKObjectSerializer.m
Blake Watters 54007c78d4 Reworked Brendan Ribera's contributions around time zone handling to eliminate the use of transient
NSDateFormatters, added a preferredDateFormatter for use when serializing dates to strings,
replaced the use of the description method for date encoding to strings with invocation of the
preferredDateFormatter, added new attribute transformation strategy from NSDate -> NSString properties
(also using the preferred date formatter), and provided customization support for date handling globally
and on a per-mapping basis. closes #200, closes #313, closes #309, closes #308
2011-09-05 17:25:43 -04:00

118 lines
3.8 KiB
Objective-C

//
// RKObjectSerializer.m
// RestKit
//
// Created by Blake Watters on 5/2/11.
// Copyright 2011 Two Toasters. All rights reserved.
//
#import "../Network/RKRequestSerialization.h"
#import "../Support/RKMIMETypes.h"
#import "../Support/RKParser.h"
#import "RKObjectSerializer.h"
#import "NSDictionary+RKRequestSerialization.h"
#import "RKParserRegistry.h"
#import "RKLog.h"
// Set Logging Component
#undef RKLogComponent
#define RKLogComponent lcl_cRestKitObjectMapping
@implementation RKObjectSerializer
@synthesize object = _object;
@synthesize mapping = _mapping;
+ (id)serializerWithObject:(id)object mapping:(RKObjectMapping*)mapping {
return [[[self alloc] initWithObject:object mapping:mapping] autorelease];
}
- (id)initWithObject:(id)object mapping:(RKObjectMapping*)mapping {
self = [super init];
if (self) {
_object = [object retain];
_mapping = [mapping retain];
}
return self;
}
- (void)dealloc {
[_object release];
[_mapping release];
[super dealloc];
}
// Return it serialized into a dictionary
- (id)serializedObject:(NSError**)error {
NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
RKObjectMappingOperation* operation = [RKObjectMappingOperation mappingOperationFromObject:_object toObject:dictionary withMapping:_mapping];
operation.delegate = self;
BOOL success = [operation performMapping:error];
if (!success) {
return nil;
}
// Optionally enclose the serialized object within a container...
if (_mapping.rootKeyPath) {
// TODO: Should log this...
dictionary = [NSMutableDictionary dictionaryWithObject:dictionary forKey:_mapping.rootKeyPath];
}
return dictionary;
}
- (id)serializedObjectForMIMEType:(NSString*)MIMEType error:(NSError**)error {
// TODO: This will fail for form encoded...
id serializedObject = [self serializedObject:error];
if (serializedObject) {
id<RKParser> parser = [[RKParserRegistry sharedRegistry] parserForMIMEType:MIMEType];
NSString* string = [parser stringFromObject:serializedObject error:error];
if (string == nil) {
return nil;
}
return string;
}
return nil;
}
- (id<RKRequestSerializable>)serializationForMIMEType:(NSString*)MIMEType error:(NSError**)error {
if ([MIMEType isEqualToString:RKMIMETypeFormURLEncoded]) {
// Dictionaries are natively RKRequestSerializable as Form Encoded
return [self serializedObject:error];
} else {
NSString* string = [self serializedObjectForMIMEType:MIMEType error:error];
if (string) {
NSData* data = [string dataUsingEncoding:NSUTF8StringEncoding];
return [RKRequestSerialization serializationWithData:data MIMEType:MIMEType];
}
}
return nil;
}
#pragma mark - RKObjectMappingOperationDelegate
- (void)objectMappingOperation:(RKObjectMappingOperation *)operation didSetValue:(id)value forKeyPath:(NSString *)keyPath usingMapping:(RKObjectAttributeMapping *)mapping {
id transformedValue = nil;
if ([value isKindOfClass:[NSDate class]]) {
// Date's are not natively serializable, must be encoded as a string
@synchronized(self.mapping.preferredDateFormatter) {
transformedValue = [self.mapping.preferredDateFormatter stringFromDate:value];
}
} else if ([value isKindOfClass:[NSDecimalNumber class]]) {
// Precision numbers are serialized as strings to work around Javascript notation limits
transformedValue = [(NSDecimalNumber*)value stringValue];
}
if (transformedValue) {
RKLogDebug(@"Serialized %@ value at keyPath to %@ (%@)", NSStringFromClass([value class]), NSStringFromClass([transformedValue class]), value);
[operation.destinationObject setValue:transformedValue forKey:keyPath];
}
}
@end