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
Allow specification of properties for serialization to JSON #185
Comments
Are you saying that you'd like to conditionalize the properties per instance? You can already omit certain keys with the implementation of |
I'd like to conditionalize the building of the JSON dictionary per serialization rather than per instance, so the same model could be used in multiple situations. I might create a model object with JSON with all properties present, but in building JSON to send to some remote server, only specific properties are serialized for sending the other way. Sorry if I'm not being clear. My use case is that I have a user model with various attributes that come from a remote server. My app allows editing of some of these values and I'd like to be able to build a JSON dictionary where the non-editable keys & values are omitted. I can see that this could be achieved by using a subclass of the fully-fledged model but this feels messy and only works for the specific set of properties defined in |
TBH, this sounds like something that'd be easier to implement manually. Mantle isn't meant to handle every possible case, just the simplest (very boilerplate-heavy) ones. We're always happy to extend it, but the additional utility has to overwhelmingly justify the increased complexity, and I'm not convinced that this use case is super common. :\ |
Could you accomplish what you want by subclassing |
This seems like a sensible approach to me, let us know if there is a way to facilitate a subclass' access to what gets serialized |
Thanks for the suggestions. I looked at this in more detail and it's not easily achievable with a subclass.
As far as I can see, Outside of MTLJSONAdapter it's possible to filter the dictionary produced by |
|
What exactly might that look like? I'm struggling to see how it would help as we can already access |
I was thinking you'd subclass // XYJSONAdapter.m
- (NSString *)JSONKeyPathForPropertyKey:(NSString *)propertyKey {
if ([self.keySubset containsObject:propertyKey]) {
return [super JSONKeyPathForPropertyKey:propertyKey]; // This checks the cached copy of the model's +JSONKeyPathsByPropertyKey
}
return nil; // i.e. don't serialize `propertyKey`
} Then you could set // XYAPIClient.m
adapter.keySubset = [NSSet setWithArray:@[ @"id", @"username" ]];
NSDictionary *idAndName = [adapter JSONDictionaryFromModel:user]; Would that work for your use case? (I assumed that we'd end up with longer lived adapters as discuessed in #151 but there'd probably be a way if we decided against that, too) |
@robb I couldn't see the wood for the trees. That would be perfect! 💗 |
FWIW I have the same use case as @dcaunt - I need to send a partial representation of an object to an API, basically a PATCH request. For now I've implemented a custom method |
@robb said:
However it demonstrates calling It also doesn't seem possible to create an adapter instance without conversion, at which point it's too late to set the property. |
Yeah, I was thinking along the lines of #151 Would it be possible to do something like this: // XYAPIClient.m
+ (NSDictionary *)JSONDictionaryFromModel:(MTLModel<MTLJSONSerializing> *)model keySubset:(NSSet *)keySubset {
MTLJSONAdapter *adapter = [[self alloc] initWithModel:model];
adapter.keySubset = keySubset;
return adapter.JSONDictionary;
} ? |
I'll probably also need to support However, my current use case only requires me to specify which subset of properties should be serialized per class. I created a protocol which extended The protocol has the optional method The rest of the implementation for |
If @robb and @jspahrsummers think this is useful I'll happily create a pull request. |
It seems like you're building this more-or-less anyway and I'd 💙 to discuss this further in a separete PR. |
@paulyoung did you implement it yet? |
Didn't this feature implemented already? |
I see there was PR But in current version I do not able to use |
I implemented it in subclass like this: #import <Mantle/Mantle.h>
@protocol SmartJSONAdapting <MTLJSONSerializing>
@optional
/// whitelist only if present
+ (NSSet<NSString *> *)propertyKeysForJSONRepresentation;
/// remove properties with `nil` value from set
+ (BOOL)withoutNil;
@end
@interface SmartJSONAdapter : MTLJSONAdapter
- (NSSet *)serializablePropertyKeys:(NSSet *)propertyKeys
forModel:(id<SmartJSONAdapting>)model;
@end
@implementation SmartJSONAdapter
- (NSSet *)serializablePropertyKeys:(NSSet *)propertyKeys
forModel:(id<SmartJSONAdapting>)model
{
if ([[model class] respondsToSelector:@selector(withoutNil)]
&& [[model class] withoutNil]) {
NSMutableSet *propertyKeys_ = [propertyKeys mutableCopy];
[propertyKeys enumerateObjectsUsingBlock:^(NSString *_Nonnull propertyKey,
BOOL * _Nonnull stop) {
if ([[NSNull null] isEqual:model.dictionaryValue[propertyKey]]) {
[propertyKeys_ removeObject:propertyKey];
}
}];
propertyKeys = [propertyKeys_ copy];
}
if ([[model class] respondsToSelector:@selector(propertyKeysForJSONRepresentation)]) {
NSMutableSet *propertyKeys_ = [propertyKeys mutableCopy];
[propertyKeys_ minusSet:[[model class] propertyKeysForJSONRepresentation]];
propertyKeys = [propertyKeys_ copy];
}
return propertyKeys;
}
@end
|
In some cases it is useful to serialize only certain model properties to JSON. For example, you might want a JSON dictionary which only contains values known to have been modified in the model.
At present,
serializeToJSONDictionary
usesself.model.dictionaryValue
which uses all property keys to generate the JSON dictionary. An additional argument would have to be added this method to take an array of property names. The existing method could wrap this and provide all keys, as this behaviour is what is required most of the time.The text was updated successfully, but these errors were encountered: