Permalink
Browse files

[#40] handle multi word class names , [#23] added unit tests for json…

… and xml serialization and deserialization. Improved serialization of NSNumber , added a way to format NSDate serialization
  • Loading branch information...
1 parent c4bd43c commit aa08bebf52b18782998d5fe7c5c29e98f8625f5f @jjburka jjburka committed Feb 17, 2009
@@ -9,10 +9,14 @@
#import <Foundation/Foundation.h>
-@interface ObjectiveResourceDateFormatter : NSObject {
+@interface ObjectiveResourceDateFormatter : NSObject
-}
+typedef enum {
+ Date = 0,
+ DateTime,
+} ORSDateFormat;
++ (void)setSerializeFormat:(ORSDateFormat)dateFormat;
+ (void)setDateFormatString:(NSString *)format;
+ (void)setDateTimeFormatString:(NSString *)format;
+ (NSString *)formatDate:(NSDate *)date;
@@ -13,7 +13,11 @@ @implementation ObjectiveResourceDateFormatter
static NSString *dateTimeFormatString = @"yyyy-MM-dd'T'HH:mm:ss'Z'";
static NSString *dateFormatString = @"yyyy-MM-dd";
+static ORSDateFormat _dateFormat;
++ (void)setSerializeFormat:(ORSDateFormat)dateFormat {
+ _dateFormat = dateFormat;
+}
+ (void)setDateFormatString:(NSString *)format {
dateFormatString = format;
@@ -27,7 +31,12 @@ + (NSString *)formatDate:(NSDate *)date {
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
[formatter setFormatterBehavior:NSDateFormatterBehavior10_4];
- [formatter setDateFormat:dateFormatString];
+ if(_dateFormat == Date) {
+ [formatter setDateFormat:dateFormatString];
+ }
+ else {
+ [formatter setDateFormat:dateTimeFormatString];
+ }
[formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT"]];
return [formatter stringFromDate:date];
@@ -0,0 +1,17 @@
+//
+// NSArray+JSONSerializableSupport.h
+// objective_support
+//
+// Created by James Burka on 2/16/09.
+// Copyright 2009 Burkaprojects. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+
+@interface NSArray(JSONSerializableSupport)
+
+- (NSString *)toJSONAs:(NSString *)rootName excludingInArray:(NSArray *)exclusions
+ withTranslations:(NSDictionary *)keyTranslations;
+
+@end
@@ -0,0 +1,35 @@
+//
+// NSArray+JSONSerializableSupport.m
+// objective_support
+//
+// Created by James Burka on 2/16/09.
+// Copyright 2009 Burkaprojects. All rights reserved.
+//
+
+#import "JSONFramework.h"
+#import "NSObject+JSONSerializableSupport.h"
+#import "NSArray+JSONSerializableSupport.h"
+
+
+@implementation NSArray(JSONSerializableSupport)
+
+- (NSString *)toJSONAs:(NSString *)rootName excludingInArray:(NSArray *)exclusions
+ withTranslations:(NSDictionary *)keyTranslations {
+
+ NSMutableString *values = [NSMutableString stringWithString:@"["];
+ BOOL comma = NO;
+ for (id element in self) {
+ if(comma) {
+ [values appendString:@","];
+ }
+ else {
+ comma = YES;
+ }
+ [values appendString:[element toJSONAs:[element jsonClassName] excludingInArray:exclusions withTranslations:keyTranslations]];
+
+ }
+ [values appendString:@"]"];
+ return values;
+}
+
+@end
@@ -19,5 +19,6 @@
- (NSString *)toJSONAs:(NSString *)rootName withTranslations:(NSDictionary *)keyTranslations;
- (NSString *)toJSONAs:(NSString *)rootName excludingInArray:(NSArray *)exclusions
withTranslations:(NSDictionary *)keyTranslations;
+- (NSString *) jsonClassName;
@end
@@ -14,8 +14,7 @@
@interface NSObject (JSONSerializableSupport_Private)
+ (id) deserializeJSON:(id)jsonObject;
-- (NSString *) convertProperty:(NSString *)propertyName;
-- (NSString *) jsonClassName;
+- (NSString *) convertProperty:(NSString *)propertyName andClassName:(NSString *)className;
@end
@implementation NSObject (JSONSerializableSupport)
@@ -84,7 +83,7 @@ + (id) deserializeJSON:(id)jsonObject {
NSDictionary *objectPropertyNames = [objectClass propertyNamesAndTypes];
for (NSString *property in [properties allKeys]) {
- NSString *propertyCamalized = [[self convertProperty:property] camelize];
+ NSString *propertyCamalized = [[self convertProperty:property andClassName:objectName] camelize];
if ([[objectPropertyNames allKeys]containsObject:propertyCamalized]) {
Class propertyClass = [self propertyClass:[objectPropertyNames objectForKey:propertyCamalized]];
[result setValue:[self deserializeJSON:[propertyClass deserialize:[properties objectForKey:property]]] forKey:propertyCamalized];
@@ -98,9 +97,9 @@ + (id) deserializeJSON:(id)jsonObject {
return result;
}
-- (NSString *) convertProperty:(NSString *)propertyName {
+- (NSString *) convertProperty:(NSString *)propertyName andClassName:(NSString *)className {
if([propertyName isEqualToString:@"id"]) {
- propertyName = [NSString stringWithFormat:@"%@_id",[self jsonClassName]];
+ propertyName = [NSString stringWithFormat:@"%@_id",className];
}
return propertyName;
}
@@ -30,23 +30,22 @@ - (id)init {
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
-
if ([@"nil-classes" isEqualToString:elementName]) {
//empty result set, do nothing
}
//Start of an array type
else if ([@"array" isEqualToString:[attributeDict objectForKey:@"type"]]) {
self.parsedObject = [NSMutableArray array];
- [self.unclosedProperties addObject:[NSArray arrayWithObjects:[elementName camelize], self.parsedObject, nil]];
- self.currentPropertyName = [elementName camelize];
+ [self.unclosedProperties addObject:[NSArray arrayWithObjects:elementName, self.parsedObject, nil]];
+ self.currentPropertyName = elementName;
}
//Start of the root object
else if (parsedObject == nil && [elementName isEqualToString:[self.targetClass xmlElementName]]) {
self.parsedObject = [[[self.targetClass alloc] init] autorelease];
- [self.unclosedProperties addObject:[NSArray arrayWithObjects:[elementName camelize], self.parsedObject, nil]];
- self.currentPropertyName = [elementName camelize];
+ [self.unclosedProperties addObject:[NSArray arrayWithObjects:elementName, self.parsedObject, nil]];
+ self.currentPropertyName = elementName;
}
else {
@@ -64,10 +63,9 @@ - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName nam
// If we recognize an element that corresponds to a known property of the current parent object, or if the
// current parent is an array then start collecting content for this child element
-
if (([self.parsedObject isKindOfClass:[NSArray class]]) ||
([[[self.parsedObject class] propertyNames] containsObject:[[self convertElementName:elementName] camelize]])) {
- self.currentPropertyName = [[self convertElementName:elementName] camelize];
+ self.currentPropertyName = [self convertElementName:elementName];
self.contentOfCurrentProperty = [NSMutableString string];
self.currentPropertyType = [attributeDict objectForKey:@"type"];
} else {
@@ -102,6 +100,12 @@ - (id) convertProperty:(NSString *)propertyValue toType:(NSString *)type {
else if ([type isEqualToString:@"date"]) {
return [NSDate fromXMLDateString:propertyValue];
}
+ else if ([type isEqualToString:@"decimal"]) {
+ return [NSDecimalNumber decimalNumberWithString:propertyValue];
+ }
+ else if ([type isEqualToString:@"integer"]) {
+ return [NSNumber numberWithInt:[propertyValue intValue]];
+ }
else {
return [NSString fromXmlString:propertyValue];
}
@@ -111,12 +115,12 @@ - (id) convertProperty:(NSString *)propertyValue toType:(NSString *)type {
- (NSString *) convertElementName:(NSString *)anElementName {
if([anElementName isEqualToString:@"id"]) {
-
- return [NSString stringWithFormat:@"%@_%@" , [NSStringFromClass([self.parsedObject class])
- stringByReplacingCharactersInRange:NSMakeRange(0, 1)
- withString:[[NSStringFromClass([self.parsedObject class])
- substringWithRange:NSMakeRange(0,1)]
- lowercaseString]], anElementName];
+ return [NSString stringWithFormat:@"%@Id",[[[self.parsedObject class]xmlElementName] camelize]];
+ // return [NSString stringWithFormat:@"%@_%@" , [NSStringFromClass([self.parsedObject class])
+// stringByReplacingCharactersInRange:NSMakeRange(0, 1)
+// withString:[[NSStringFromClass([self.parsedObject class])
+// substringWithRange:NSMakeRange(0,1)]
+// lowercaseString]], anElementName];
}
else {
@@ -133,9 +137,9 @@ - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName names
if(self.contentOfCurrentProperty != nil && self.currentPropertyName != nil) {
[self.parsedObject
setValue:[self convertProperty:self.contentOfCurrentProperty toType:self.currentPropertyType]
- forKey:self.currentPropertyName];
+ forKey:[self.currentPropertyName camelize]];
}
- else if ([self.currentPropertyName isEqualToString:[self convertElementName:[elementName camelize]]]) {
+ else if ([self.currentPropertyName isEqualToString:[self convertElementName:elementName]]) {
//element is closed, pop it from the stack
[self.unclosedProperties removeLastObject];
//check for a parent object on the stack
@@ -22,4 +22,14 @@ - (NSString *)toXMLValue {
return result;
}
+- (NSString *)toXMLElementAs:(NSString *)rootName excludingInArray:(NSArray *)exclusions
+ withTranslations:(NSDictionary *)keyTranslations {
+ NSMutableString *elementValue = [NSMutableString string];
+ for (id element in self) {
+ [elementValue appendString:[element toXMLElementAs:[[element class] xmlElementName] excludingInArray:exclusions withTranslations:keyTranslations]];
+ }
+ return [[self class] buildXmlElementAs:rootName withInnerXml:elementValue andType:@"array"];
+}
+
+
@end
@@ -7,6 +7,7 @@
//
#import "NSDate+XMLSerializableSupport.h"
+#import "NSObject+XMLSerializableSupport.h"
#import "ObjectiveResourceDateFormatter.h"
@implementation NSDate (XMLSerializableSupport)
@@ -17,6 +18,11 @@ - (NSString *)toXMLValue {
return [ ObjectiveResourceDateFormatter formatDate:self];
}
+- (NSString *)toXMLElementAs:(NSString *)rootName excludingInArray:(NSArray *)exclusions
+ withTranslations:(NSDictionary *)keyTranslations {
+ return [[self class] buildXmlElementAs:rootName withInnerXml:[self toXMLValue] andType:[[self class] xmlTypeFor:self]];
+}
+
+ (NSDate *)fromXMLDateTimeString:(NSString *)xmlString {
return [ ObjectiveResourceDateFormatter parseDateTime:xmlString];
}
@@ -6,9 +6,11 @@
// Copyright 2008 yFactorial, LLC. All rights reserved.
//
-#import "ComplexXMLSerializable.h"
-@interface NSDictionary (XMLSerializableSupport) <ComplexXMLSerializable>
+@interface NSDictionary (XMLSerializableSupport)
+
+- (NSString *)toXMLElementAs:(NSString *)rootName excludingInArray:(NSArray *)exclusions
+ withTranslations:(NSDictionary *)keyTranslations andType:(NSString *)xmlType;
- (NSString *)toXMLElementAs:(NSString *)rootName excludingInArray:(NSArray *)exclusions
withTranslations:(NSDictionary *)keyTranslations;
@@ -12,10 +12,9 @@
@implementation NSDictionary (XMLSerializableSupport)
-
- (NSString *)toXMLElementAs:(NSString *)rootName excludingInArray:(NSArray *)exclusions
- withTranslations:(NSDictionary *)keyTranslations {
-
+ withTranslations:(NSDictionary *)keyTranslations andType:(NSString *)xmlType {
+
NSMutableString* elementValue = [NSMutableString string];
id value;
NSString *propertyRootName;
@@ -27,7 +26,12 @@ - (NSString *)toXMLElementAs:(NSString *)rootName excludingInArray:(NSArray *)ex
[elementValue appendString:[value toXMLElementAs:propertyRootName]];
}
}
- return [[self class] buildXmlElementAs:rootName withInnerXml:elementValue];
+ return [[self class] buildXmlElementAs:rootName withInnerXml:elementValue andType:xmlType];
+}
+
+- (NSString *)toXMLElementAs:(NSString *)rootName excludingInArray:(NSArray *)exclusions
+ withTranslations:(NSDictionary *)keyTranslations {
+ return [self toXMLElementAs:rootName excludingInArray:exclusions withTranslations:keyTranslations andType:nil];
}
@end
@@ -0,0 +1,12 @@
+//
+// NSNumber+XMLSerializableSupport.h
+// objective_support
+//
+// Created by James Burka on 2/17/09.
+// Copyright 2009 Burkaprojects. All rights reserved.
+//
+
+@interface NSNumber(XMLSerializableSupport)
+- (NSString *)toXMLValue;
+
+@end
@@ -0,0 +1,25 @@
+//
+// NSNumber+XMLSerializableSupport.m
+// objective_support
+//
+// Created by James Burka on 2/17/09.
+// Copyright 2009 Burkaprojects. All rights reserved.
+//
+
+#import "NSObject+XMLSerializableSupport.h"
+#import "NSNumber+XMLSerializableSupport.h"
+
+
+@implementation NSNumber(XMLSerializableSupport)
+
+- (NSString *)toXMLValue {
+ return [self stringValue];
+}
+
+- (NSString *)toXMLElementAs:(NSString *)rootName excludingInArray:(NSArray *)exclusions
+ withTranslations:(NSDictionary *)keyTranslations {
+ return [[self class] buildXmlElementAs:rootName withInnerXml:[self toXMLValue] andType:[[self class] xmlTypeFor:self]];
+}
+
+
+@end
@@ -10,6 +10,9 @@
@interface NSObject (XMLSerializableSupport) <XMLSerializable>
++ (NSString *)xmlTypeFor:(NSObject *)value;
++ (NSString *)buildXmlElementAs:(NSString *)rootName withInnerXml:(NSString *)value andType:(NSString *)xmlType;
+
/**
* Construct a string representation of the given value object, assuming
* the given root element name , the NSObjects's toXmlValue is called.
@@ -7,6 +7,7 @@
//
#import "NSObject+XMLSerializableSupport.h"
+#import "NSDictionary+XMLSerializableSupport.h"
#import "CoreSupport.h"
#import "FromXMLElementDelegate.h"
@@ -44,8 +45,7 @@ + (NSString *)xmlTypeFor:(NSObject *)value {
}
}
-+ (NSString *)buildXmlElementAs:(NSString *)rootName withInnerXml:(NSString *)value {
- NSString *xmlType = [self xmlTypeFor:value];
++ (NSString *)buildXmlElementAs:(NSString *)rootName withInnerXml:(NSString *)value andType:(NSString *)xmlType{
NSString *dashedName = [rootName dasherize];
if (xmlType != nil) {
@@ -55,13 +55,17 @@ + (NSString *)buildXmlElementAs:(NSString *)rootName withInnerXml:(NSString *)va
}
}
++ (NSString *)buildXmlElementAs:(NSString *)rootName withInnerXml:(NSString *)value {
+ return [[self class] buildXmlElementAs:rootName withInnerXml:value andType:nil];
+}
+
+ (NSString *)buildXMLElementAs:(NSString *)rootName withValue:(NSObject *)value {
- return [[self class] buildXmlElementAs:rootName withInnerXml:[value toXMLValue]];
+ return [[self class] buildXmlElementAs:rootName withInnerXml:[value toXMLValue] andType:[self xmlTypeFor:value]];
}
+ (NSString *)xmlElementName {
NSString *className = NSStringFromClass(self);
- return [className stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:[[className substringToIndex:1] lowercaseString]];
+ return [[className stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:[[className substringToIndex:1] lowercaseString]] dasherize];
}
# pragma mark XMLSerializable implementation methods
@@ -91,7 +95,7 @@ - (NSString *)toXMLElementAs:(NSString *)rootName withTranslations:(NSDictionary
**/
- (NSString *)toXMLElementAs:(NSString *)rootName excludingInArray:(NSArray *)exclusions
withTranslations:(NSDictionary *)keyTranslations {
- return [[self properties] toXMLElementAs:rootName excludingInArray:exclusions withTranslations:keyTranslations];
+ return [[self properties] toXMLElementAs:rootName excludingInArray:exclusions withTranslations:keyTranslations andType:[[self class] xmlTypeFor:self]];
}
# pragma mark XML Serialization convenience methods
Oops, something went wrong.

0 comments on commit aa08beb

Please sign in to comment.