Framework/ROADSerialization/ROADSerialization/JSON/RFAttributedCoder.m (162 lines of code) (raw):
//
// RFAnnotatedCoder.m
// ROADSerialization
//
// Copyright (c) 2014 EPAM Systems, Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// Redistributions in binary form must reproduce the above copyright notice, this
// list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
// Neither the name of the EPAM Systems, Inc. nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// See the NOTICE file and the LICENSE file distributed with this work
// for additional information regarding copyright ownership and licensing
#import <ROAD/ROADReflection.h>
#import <ROAD/ROADCore.h>
#import "RFAttributedCoder.h"
#import "RFSerializationLog.h"
#import "RFSerializable.h"
#import "RFDerived.h"
#import "RFSerializableDate.h"
#import "RFSerializationCustomHandler.h"
#import "RFJSONSerializationHandling.h"
#import "RFSerializableBoolean.h"
#import "RFBooleanTranslator.h"
#import "RFSerializationAssistant.h"
@implementation RFAttributedCoder {
NSString * _dateFormat;
id _archive;
NSString * _currentPath;
RFObjectPool* _dateFormattersPool;
}
#pragma mark - Initialization
- (id)init {
self = [super init];
if (self) {
_archive = [[NSMutableDictionary alloc] init];
_dateFormattersPool = RFCreateDateFormatterPool();
}
return self;
}
#pragma mark - Encoding
+ (NSData *)encodedDataOfRootObject:(id)rootObject {
return [self encodedDataOfRootObject:rootObject options:NSJSONWritingPrettyPrinted | NSJSONReadingAllowFragments error:nil];
}
+ (NSData *)encodedDataOfRootObject:(id)rootObject options:(NSJSONWritingOptions)options error:(NSError * __autoreleasing *)error {
id serializableObject = [self encodeRootObjectToSerializableObject:rootObject];
NSError *internalError = nil;
id result = [NSJSONSerialization dataWithJSONObject:serializableObject options:options error:&internalError];
if (internalError) {
*error = internalError;
RFSCLogError(@"ROADSerialization: Error when encoding object %@ :\n%@", rootObject, error);
}
return result;
}
+ (id)encodeRootObject:(id)rootObject options:(NSJSONWritingOptions)options error:(NSError *__autoreleasing *)error {
NSData *data = [self encodedDataOfRootObject:rootObject options:options error:error];
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
+ (id)encodeRootObject:(id)rootObject {
NSData *data = [self encodedDataOfRootObject:rootObject];
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
+ (id)encodeRootObjectToSerializableObject:(id)rootObject {
RFSCLogInfo(@"Coder(%@ %p) started processing object(%@)", self, self, rootObject);
RFAttributedCoder *coder = [[self alloc] init];
coder->_archive = [coder encodeRootObject:rootObject];
RFSCLogInfo(@"Coder(%@ %p) ended processing", self, self);
return coder->_archive;
}
- (id)encodeRootObject:(id)rootObject {
id archive;
if ([rootObject isKindOfClass:[NSArray class]]) {
archive = [self encodeArray:rootObject customHandlerAttribute:nil];
}
else if ([rootObject isKindOfClass:[NSDictionary class]]) {
archive = [self encodeDictionary:rootObject customHandlerAttribute:nil];
}
else {
RFSerializationCustomHandler *customHandlerAttribute = [[rootObject class] RF_attributeForClassWithAttributeType:[RFSerializationCustomHandler class]];
if (customHandlerAttribute.handlerClass && customHandlerAttribute.key.length == 0) {
archive = RFCustomSerialization(rootObject, customHandlerAttribute);
}
else {
archive = [[NSMutableDictionary alloc] init];
RFSerializable *serializableAttribute = [[rootObject class] RF_attributeForClassWithAttributeType:[RFSerializable class]];
if (serializableAttribute && !serializableAttribute.classNameSerializationDisabled) {
archive[RFSerializedObjectClassName] = NSStringFromClass([rootObject class]);
}
NSArray *properties = RFSerializationPropertiesForClass([rootObject class]);
@autoreleasepool {
[self fillDictionary:archive withProperties:properties rootObject:rootObject customHandlerAttribute:customHandlerAttribute];
}
}
}
return archive;
}
- (void)fillDictionary:(NSMutableDictionary *)archive withProperties:(NSArray *)properties rootObject:(id)rootObject customHandlerAttribute:(RFSerializationCustomHandler *)customHandlerAttribute {
for (RFPropertyInfo * const aDesc in properties) {
NSString *propertyName = [aDesc propertyName];
id value = [rootObject valueForKey:propertyName];
id encodedValue;
if ([customHandlerAttribute.key isEqualToString:propertyName]) {
encodedValue = RFCustomSerialization(value, customHandlerAttribute);
}
else {
RFSerializationCustomHandler *propertyCustomHandlerAttribute = [aDesc attributeWithType:[RFSerializationCustomHandler class]];
if (propertyCustomHandlerAttribute.handlerClass && propertyCustomHandlerAttribute.key.length == 0) {
encodedValue = RFCustomSerialization(value, propertyCustomHandlerAttribute);
}
else {
encodedValue = [self encodeValue:value forProperty:aDesc customHandlerAttribute:propertyCustomHandlerAttribute];
}
}
NSString *key = RFSerializationKeyForProperty(aDesc);
if (encodedValue != nil) {
archive[key] = encodedValue;
}
}
}
- (id)encodeValue:(id)value forProperty:(RFPropertyInfo *)propertyInfo customHandlerAttribute:(RFSerializationCustomHandler *)customHandlerAttribute {
id encodedValue = nil;
// Custom preprocessing. Does not replace default handling
if (customHandlerAttribute.encodingPreprocessor) {
value = customHandlerAttribute.encodingPreprocessor(value);
}
if ([value isKindOfClass:[NSDate class]]) {
encodedValue = RFSerializationEncodeDateForProperty(value, propertyInfo, _dateFormattersPool);
}
else if ([propertyInfo attributeWithType:[RFSerializableBoolean class]]) {
encodedValue = [RFBooleanTranslator encodeTranslatableValue:value forProperty:propertyInfo];
}
else {
encodedValue = [self encodeValue:value customHandlerAttribute:customHandlerAttribute];
}
return encodedValue;
}
- (id)encodeValue:(id)value customHandlerAttribute:(RFSerializationCustomHandler *)customHandlerAttribute {
id encodedValue;
if ([[value class] RF_attributeForClassWithAttributeType:[RFSerializable class]] || [[[value class] RF_propertiesWithAttributeType:[RFSerializable class]] count] > 0) {
encodedValue = [self encodeRootObject:value];
}
else if ([value isKindOfClass:[NSArray class]]) {
encodedValue = [self encodeArray:value customHandlerAttribute:customHandlerAttribute];
}
else if ([value isKindOfClass:[NSDictionary class]]) {
encodedValue = [self encodeDictionary:value customHandlerAttribute:customHandlerAttribute];
}
else if ([value isKindOfClass:[NSDate class]]) {
encodedValue = [value description];
}
else {
encodedValue = value;
}
return encodedValue;
}
- (id)encodeArray:(NSArray *)anArray customHandlerAttribute:(RFSerializationCustomHandler *)customHandlerAttribute {
NSMutableArray *array = [NSMutableArray array];
for (id aValue in anArray) {
[array addObject:[self encodeValue:aValue customHandlerAttribute:customHandlerAttribute]];
}
return [NSArray arrayWithArray:array];
}
- (id)encodeDictionary:(NSDictionary *)aDict customHandlerAttribute:(RFSerializationCustomHandler *)customHandlerAttribute {
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
for (id aKey in aDict) {
id aValue = aDict[aKey];
if ([customHandlerAttribute.key isEqualToString:aKey]) {
dict[aKey] = RFCustomSerialization(aValue, customHandlerAttribute);
}
else {
dict[aKey] = [self encodeValue:aValue customHandlerAttribute:customHandlerAttribute];
}
}
return [NSDictionary dictionaryWithDictionary:dict];
}
@end