-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Value transformers are not applied on POST body data #1949
Comments
Create a custom |
I guess the markdown destroyed the part where I said I had a custom RKValueTransformer. The issue is that the RKValueTransformers are NOT used prior to the JSON serialization layer on the way out. Please re-open the issue, or provide me with a code path to follow 'cas I can't see it. |
Please share the code in which you assign the transformer to the mapping? |
The transformer is global:
|
Following the code path for creating a POST request, it looks like the issue is in RKObjectParameterization.m
Issue is in
This consistently returns nil for the value class, so no transform is done. If this returned a NSString class type, then the value transformer should get invoked - if I understand this correctly... |
@blakewatters this should probably change to use a value transformer for everything so it is customizable... |
I figured out what is up. From the documentation on RKPropertyMapping:
I was able to set this for value I have, which invokes the value transformer. |
@emlynmac: Can you post a Gist or something of your final code? I'm trying to do the same thing with a NSURL, and there are a couple of missing pieces that I'm not following. |
@emlynmac Can you elaborate on your fix? I am having a similar issue and can't get my custom transformer to be used at the serialization layer. |
In my case I needed to convert for responses and requests millisecond timestamps. Responses worked by default after set a custom value transformer. The problem was that it wasn't taken into consideration at request time. In request mapping I solved it by setting the [mapping addAttributeMappingsFromDictionary:@{ @"content" : @"content",
@"messageLocalID" : @"local_id",
@"createdLocallyAt" : @"created_locally_at",
}];
[mapping.propertyMappings enumerateObjectsUsingBlock:^(RKAttributeMapping* _Nonnull attributeMapping, NSUInteger idx, BOOL * _Nonnull stop) {
if ([attributeMapping.sourceKeyPath isEqualToString:@"createdLocallyAt"]) {
attributeMapping.propertyValueClass = [NSNumber class];
*stop = YES;
}
}];
Custom Value Transformer - (RKBlockValueTransformer*)timeIntervalSince1970ToDateValueTransformerDouble
{
if(!_timeIntervalSince1970ToDateValueTransformerDouble){
_timeIntervalSince1970ToDateValueTransformerDouble = [RKBlockValueTransformer valueTransformerWithValidationBlock:^BOOL(__unsafe_unretained Class inputValueClass, __unsafe_unretained Class destinationClass){
return ((([inputValueClass isSubclassOfClass:[NSString class]] || [inputValueClass isSubclassOfClass:[NSNumber class]]) && [destinationClass isSubclassOfClass:[NSDate class]]) || ([inputValueClass isSubclassOfClass:[NSDate class]] && ([destinationClass isSubclassOfClass:[NSNumber class]] || [destinationClass isSubclassOfClass:[NSString class]])));
} transformationBlock:^BOOL(id inputValue,
__autoreleasing id *outputValue,
__unsafe_unretained Class outputClass,
NSError *__autoreleasing *error) {
static dispatch_once_t onceToken;
static NSArray *validClasses;
static NSNumberFormatter *numberFormatter;
dispatch_once(&onceToken, ^{
validClasses = @[ [NSNumber class], [NSString class], [NSDate class] ];
numberFormatter = [NSNumberFormatter new];
numberFormatter.numberStyle = NSNumberFormatterDecimalStyle;
});
RKValueTransformerTestInputValueIsKindOfClass(inputValue, validClasses, error);
RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputClass, validClasses, error);
if ([outputClass isSubclassOfClass:[NSDate class]]) {
if ([inputValue isKindOfClass:[NSNumber class]]) {
*outputValue = [NSDate dateWithTimeIntervalSince1970:([inputValue doubleValue] / 1000.0f)];
} else if ([inputValue isKindOfClass:[NSString class]]) {
if ([[inputValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] == 0) {
*outputValue = nil;
return YES;
}
NSString *errorDescription = nil;
NSNumber *formattedNumber;
BOOL success = [numberFormatter getObjectValue:&formattedNumber forString:inputValue errorDescription:&errorDescription];
RKValueTransformerTestTransformation(success, error, @"%@", errorDescription);
*outputValue = [NSDate dateWithTimeIntervalSince1970:[formattedNumber doubleValue]];
}
} else if ([outputClass isSubclassOfClass:[NSNumber class]]) {
*outputValue = @((long long)([inputValue timeIntervalSince1970] * 1000.0f));
} else if ([outputClass isSubclassOfClass:[NSString class]]) {
*outputValue = [numberFormatter stringForObjectValue:@([inputValue timeIntervalSince1970])];
}
return YES;
}];
}
return _timeIntervalSince1970ToDateValueTransformerDouble;
}
|
I use NSManagedObjects to replicate a remote endpoint. One of these parameters is passed from the server as BASE64 encoded binary data, which I have implemented a custom NSObject RKValueTransforming class to handle. The API also uses a UNIX time convention, which works well when retrieving the object.
When POSTing back to the server, these values are not transformed, and in some cases will cause a crash in the JSON serialization layer - when it does not adhere to NSCoding.
After digging a little through the code, I see that RKMappingOperations handle the work of transforming the parameters in the - (BOOL)transformValue:(id)inputValue toValue:(__autoreleasing id *)outputValue withPropertyMapping:(RKPropertyMapping *)propertyMapping error: method.
I'm going to see how hard it would be to add this to the outgoing POST requests so that values are transformed on the way out too.
The text was updated successfully, but these errors were encountered: