Restkit is mapping my date just fine to an object, but when trying to do an inverse mapping back to json i'm getting this error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: 'Invalid type in JSON write (__NSDate)'
Obviously this is an issue with the json parser for iOS, but I figured the inverse should be handled by RestKit as well. Anyone else experience this or have a solution?
In logging restkit I get this message right before:
D restkit.object_mapping:RKMappingOperation.m:920 Finished mapping operation successfully...
**EDIT:
Mapping example:
// Define media mapping
RKObjectMapping *mediaMapping = [Media getObjectMapping];
// Define Post mapping
RKObjectMapping *postMapping = [RKObjectMapping mappingForClass:[self class]];
[postMapping addAttributeMappingsFromDictionary:#{
#"post_id": #"postID",
#"userID": #"userID",
#"title": #"title",
#"favorite": #"favorite",
#"created": #"created",
#"modified": #"modified"}];
// Define relationship in the mapping between Media and Post
[postMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"media"
toKeyPath:#"media"
withMapping:mediaMapping]];
Discriptor example:
RKObjectMapping *entityMapping = [object getObjectMapping];
RKResponseDescriptor *successDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping
method:RKRequestMethodPOST
pathPattern:request.URL.relativePath
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
**UPDATE2:
Right from the dictionary I break point and inspected the offending value in the destination object.
[11] = #"created" : 2014-04-21 11:04:43 PDT
key __NSCFConstantString * #"created" 0x002d3818
value __NSDate * 2014-04-21 11:04:43 PDT 0x155bab10
I can see the issue, it appears to be passing the dictionary with the NSDate to [NSJSONSerialization dataWithJSONObject: options: error:] via this method, [RKSerialization dataFromObject: error;
Should RestKit not be converting the NSDate using the RKValueTransformer I have defined before passing to NSJSONSerialization?
Open issue at github can be found here.
Related
I want to get transaction details using Solana API with python. There are two documents for it.
1: https://docs.solana.com/developing/clients/jsonrpc-api#gettransaction
2: https://michaelhly.github.io/solana-py/rpc/api/#solana.rpc.api.Client.get_transaction
I used this code below
solana_client = Client("https://api.mainnet-beta.solana.com")
from solders.signature import Signature
sig = Signature.from_string("3NHUEPkc7a2mPkC51umAbLdNjrwoEaCXfdJ7BjHaEhYPchy5TtrCifbJqSujyZCNRuDKDfJvpN8osx9KvSWdwMp8")
solana_client.get_transaction(sig).value.block_time
and I got multiple errors
TypeError: Object of type Signature is not JSON serializable
TypeError: dict had unencodable value at keys: {params: because (list had unencodable value at index: [0: because (Object of type Signature is not JSON serializable)])}
TypeError: Could not encode to JSON
Any idea how can i handle this error?
I'm trying to deserialize some JSON coming back from couchbase into a dynamic type.
The document is something like this so creating a POCO for this would be overkill:
{
UsersOnline: 1
}
I figured that something like this would do the trick, but it seems to deserialize into a dynamic object with the value just being the original JSON
var jsonObj = _client.GetJson<dynamic>(storageKey);
results in:
jsonObj { "online": 0 }
Is there anyway I can get the couchbase deserializer to generate the dynamic type for me?
Cheers
The default deserializer for the client uses .NET's binary serializer, so when you save or read a JSON string, it's just a string. GetJson will always just return a string. However, there are a couple of options:
You could convert JSON records to Dictionary instances:
var appJson = "{ \"UsersOnline\" : 1, \"NewestMember\" : \"zblock\" }";
var result = client.ExecuteStore(StoreMode.Set, "userCount", appJson);
var item = client.GetJson<Dictionary<string, object>>("userCount");
Console.WriteLine("There are {0} users online. The newest member is {1}.",
item["UsersOnline"], item["NewestMember"]);
Or you could use a dynamic ExpandoObject instance:
var appJson = "{ \"UsersOnline\" : 1, \"NewestMember\" : \"zblock\" }";
var result = client.ExecuteStore(StoreMode.Set, "userCount", appJson);
dynamic item = client.GetJson<ExpandoObject>("userCount");
Console.WriteLine("There are {0} users online. The newest member is {1}.",
item.UsersOnline, item.NewestMember);
In either case you're losing static type checking, which seems like it's OK for your purposes. In both cases you get access to the JSON properties without having to parse the JSON into a POCO though...
Edit: I wrote a couple of extension methods that may be useful and blogged about them at http://blog.couchbase.com/moving-no-schema-stack-c-and-dynamic-types
If I'm getting back an array of objects in JSON, and I've set a mapping for those objects, why does RestKit only return me one object instead of an array?
RestKit gives this output in the log:
Coerced object mapping result containing 10 objects into singular result.
This depends on the Method you invoke on the RKObjectMappingResult.
...
yourMapping = [RKObjectMapping mappingForClass:[YourExchangeObject class]];
[yourMapping mapKeyPath:#"attribute" toAttribute:#"attribute"];
...
RKObjectMappingProvider *provider = [RKObjectMappingProvider new];
[provider setMapping:yourMapping forKeyPath:#""];
RKObjectMapper *mapper = [RKObjectMapper mapperWithObject:parsedData mappingProvider:provider];
RKObjectMappingResult *mappingResult = [mapper performMapping];
so now if you call
NSObject *object = [mappingResult asObject];
you'll get the "Coerced object mapping result containing ..." warning and only one result will be deliverd
call instead
NSArray *array = [mappingResult asCollection];
and it should work
I'm trying to serialize scala case class to JSON string using Jerkson like this:
case class Page(title: String, id: String, ls: List[(String, String, Int)])
val pageList = new mutable.ArrayBuffer[Page]()
val jsonString = Json.generate(pageList)
pageList is extremely large with several million Page objects.
The call fails with this exception:
Caused by: org.codehaus.jackson.map.JsonMappingException:
[no message for java.lang.ArrayIndexOutOfBoundsException]
You may want to consider using a Streaming solution. You can use one of the the Jackson Streaming APIs:
JsonGenerator jg = jsonFactory.createJsonGenerator(file, JsonEncoding.UTF8); // or Stream, Reader
or, you can use a TokenBuffer (which is considered best practice for some situations):
TokenBuffer buffer = new TokenBuffer();
// serialize object as JSON tokens (but don't serialize as JSON text!)
objectMapper.writeValue(buffer, myBean);
Details: Jackson Streaming Documentation
Given that you've got "several million" objects, I'm guessing you might be hitting the length limit of String. Try generating to an OutputStream, ie, Json.generate(pageList, out).
I have the following NancyFX unit test. I use the Shouldly assertion library to give the set of extensions methods that start .Should---
[Fact]
public void Assessment__Should_return_assessment_state_for_specified_user()
{
const AssessmentState assessmentState = AssessmentState.Passed;
var user = Fake.Mentor();
using (var db = Fake.Db())
{
db.Save(user);
Fake.Assessment(user.Id, db, assessmentState);
db.ClearStaleIndexes();
}
var response = Fake.Browser(user.UserName, user.Password)
.Get("/assessment/state/" + user.Id, with => with.HttpRequest());
//var result = (dynamic)body.DeserializeJson<ExpandoObject>();
var result = (dynamic) JsonConvert.DeserializeObject<ExpandoObject>(response.Body.AsString());
result.ShouldNotBe(null);
((AssessmentState) result.State).ShouldBe(assessmentState);
}
This test calls a AssessmentService uri defined as /assessment/state/" + user.Id which returns a simple JSON object definition that has a single property State of type (enum) AssessmentState, either Passed, Failed or NotStarted.
Here is the service handler so you can see there are no tricks.
Get["/assessment/state/{userid}"] = parameters =>
{
var assessment = AssessmentService.GetByUserId(Db, (string)parameters.userid);
return assessment == null ? HttpStatusCode.NotFound : Response.AsJson(new
{
assessment.State
});
};
And here is an example the JSON this service call returns:
{"State":1}
Everything works fine until I try to Deserialize the JSON returned by the fake Nancy browser. First I tried to use the built in method provided by Nancy's BrowserResponse.Body object:
var result = (dynamic)response.Body.DeserializeJson<ExpandoObject>();
This deserializes to an empty object. Which is no good. However, if we use the Newtonsoft equivalent then everything is fine (almost).
var result = (dynamic) JsonConvert.DeserializeObject<ExpandoObject>(response.Body.AsString());
The JSON deserialization now works and so the following Shouldly assertion passes with flying colours:
((AssessmentState) result.State).ShouldBe(assessmentState);
However, for reasons that I suspect have to do with anonymous types, the following line fails at run-time (it compiles fine).
result.ShouldNotBe(null);
That is quite a lot of information. Let me distil it down to two questions:
Why does Nancy's built in JSON deserializer not work given that the Newtonsoft version does?
How do I work with the dynamic types generated by the JSON de-serialisation so that the Shouldly extension methods do not cause a run-time exception?
Thanks
I can't answer the first question, but WRT Shouldly and dynamic types, Shouldly's ShouldNotBe method is an extension method on object. The DLR doesn't allow you to call extension methods on objects typed as dynamic (hence the runtime binder exception you're seeing)
I'd suggest that if you want to call ShouldNotBe(null) on result, you'd have to cast it to an object first (ie: ((object)result).ShouldNotBe(null))
-x