Skip to content

Commit

Permalink
[#40] handle multi word class names , [#23] added unit tests for json…
Browse files Browse the repository at this point in the history
… and xml serialization and deserialization. Improved serialization of NSNumber , added a way to format NSDate serialization
  • Loading branch information
jjburka committed Feb 17, 2009
1 parent c4bd43c commit aa08beb
Show file tree
Hide file tree
Showing 21 changed files with 298 additions and 38 deletions.
8 changes: 6 additions & 2 deletions Classes/lib/Core/ObjectiveResourceDateFormatter.h
Expand Up @@ -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;
Expand Down
11 changes: 10 additions & 1 deletion Classes/lib/Core/ObjectiveResourceDateFormatter.m
Expand Up @@ -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;
Expand All @@ -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];

Expand Down
17 changes: 17 additions & 0 deletions Classes/lib/Serialization/JSON/NSArray+JSONSerializableSupport.h
@@ -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
35 changes: 35 additions & 0 deletions Classes/lib/Serialization/JSON/NSArray+JSONSerializableSupport.m
@@ -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
Expand Up @@ -19,5 +19,6 @@
- (NSString *)toJSONAs:(NSString *)rootName withTranslations:(NSDictionary *)keyTranslations;
- (NSString *)toJSONAs:(NSString *)rootName excludingInArray:(NSArray *)exclusions
withTranslations:(NSDictionary *)keyTranslations;
- (NSString *) jsonClassName;

@end
Expand Up @@ -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)
Expand Down Expand Up @@ -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];
Expand All @@ -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;
}
Expand Down
34 changes: 19 additions & 15 deletions Classes/lib/Serialization/XML/FromXMLElementDelegate.m
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down Expand Up @@ -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];
}
Expand All @@ -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 {

Expand All @@ -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
Expand Down
10 changes: 10 additions & 0 deletions Classes/lib/Serialization/XML/NSArray+XMLSerializableSupport.m
Expand Up @@ -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
6 changes: 6 additions & 0 deletions Classes/lib/Serialization/XML/NSDate+XMLSerializableSupport.m
Expand Up @@ -7,6 +7,7 @@
//

#import "NSDate+XMLSerializableSupport.h"
#import "NSObject+XMLSerializableSupport.h"
#import "ObjectiveResourceDateFormatter.h"

@implementation NSDate (XMLSerializableSupport)
Expand All @@ -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];
}
Expand Down
Expand Up @@ -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;
Expand Down
Expand Up @@ -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;
Expand All @@ -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
12 changes: 12 additions & 0 deletions Classes/lib/Serialization/XML/NSNumber+XMLSerializableSupport.h
@@ -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
25 changes: 25 additions & 0 deletions Classes/lib/Serialization/XML/NSNumber+XMLSerializableSupport.m
@@ -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
Expand Up @@ -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.
Expand Down
14 changes: 9 additions & 5 deletions Classes/lib/Serialization/XML/NSObject+XMLSerializableSupport.m
Expand Up @@ -7,6 +7,7 @@
//

#import "NSObject+XMLSerializableSupport.h"
#import "NSDictionary+XMLSerializableSupport.h"
#import "CoreSupport.h"
#import "FromXMLElementDelegate.h"

Expand Down Expand Up @@ -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) {
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit aa08beb

Please sign in to comment.