JsonIdentityInfo causes objects to be serialized as Ids, and then cant deserialize them - jackson

I have a problem with array deserialization when using JsonIdentityInfo. The serialization takes place correctly and the array contains a few Ids where there are cyclic references. However, I cannot figure out how to deserialize the ids into objects. I get an array with some objects and some strings. [I use UUIDs for ids
#JsonIdentityInfo(
generator=ObjectIdGenerators.UUIDGenerator.class,
property="_lineItemExternalId",
scope=LineItemExternal.class
)
The array is serialized as
{
"#class":".WebServiceResponseArrayImpl",
"responseCode":0,
"responseMessage":"OK",
"systemTime":1486803868384,
"data":[
"[Ljava.io.Serializable;",
[
[
"in.cloudnine.nanoerp.model.inventory.LineItemExternal",
{
"lineItemExternalId":"0379de02-d67d-42b1-a764-d2c53f90e474",
"bags":40,
"serialNumber":"1",
"kgs":2000.00,
"manufacturerBatchNumber":"55",
"rate":250.00,
"subtotal":500000.00,
"virgin":true,
"color":{
"_colorId":"4a811a32-2057-4759-b07f-3d70f1a8ec4a",
"company":"abb1f7e2-c42f-43e6-8b44-341fe744d4c2",
"date":"2017-01-22",
"createdOn":"2017-02-09",
"modifiedOn":"2017-02-09",
"systemUser":"f46e9a61-670d-491c-8571-ba7b2e1a55e7",
"colorId":"85f91038-1e6a-4c73-a2f6-4c0e16e48f7f",
"code":"MG",
"name":"Magenta",
"value":null
},
"manufacturer":{
"_manufacturerId":"80a63b5e-33db-4b13-84cc-b9f591ea6b78"
}
}
],
"cee9d79b-77a9-4b3b-a376-ead1d6347d03",
"a15661e1-b4d4-4145-8db8-4e66ad0e4f81"
]
]
}
Here, "cee9d79b-77a9-4b3b-a376-ead1d6347d03", and "a15661e1-b4d4-4145-8db8-4e66ad0e4f81" are LineItemExternal ids, which have been serialized completely in the above json. [Removed for brevity]
The code which throws the error is
Object[]array=createBeanArrayLineItemExternal();
System.out.println("Length of Array:"+array.length);
for(Object obj:array){
LineItemExternal item=(LineItemExternal)obj;
System.out.println(item);
}
}
catch(ClassCastException e){
e.printStackTrace();
}
It throws ClassCastException saying String cannot be cast to LineItemExternal. This means the array contains one object and two strings [the Ids]
Do I need a custom deserializer or is it possible to configure object mapper to do that automatically?
I previously asked the question on disqus and the link to the project src is below.
https://github.com/ks1974in/DeserializationTestForJson.git
The sample input json is in file input.json in the project folder. The test case is in package in.cloudnine.inventory.test;
It is TestSerializationAndDeserialization
The failing test is testWithFile()
Sorry for including so much code. But the previous tests with limited code ALL SUCCEEDED. However, the above test does fail with a class cast exception
Thanks,
Sagar
Please help me.

Related

Extracting Nested POJO Object with Rest-Assured

I'm writing some tests using rest-assured and its Kotlin extensions to test some simple Spring MVC endpoints. I'm trying to understand how to extract values.
One endpoint returns a BookDetailsView POJO, the other returns a Page<BookDetailsView> (where Page is an interface provided by Spring for doing paging).
BookDetailsView is a really simple Kotlin data class with a single field:
data class BookDetailsView(val id: UUID)
For the single object endpoint, I have:
#Test
fun `single object`() {
val details = BookDetailsView(UUID.randomUUID())
whenever(bookDetailsService.getBookDetails(details.id)).thenReturn(details)
val result: BookDetailsView = Given {
mockMvc(mockMvc)
} When {
get("/book_details/${details.id}")
} Then {
statusCode(HttpStatus.SC_OK)
} Extract {
`as`(BookDetailsView::class.java)
}
assertEquals(details.id, result.id)
}
This works as expected, but trying to apply the same technique for the Page<BookDetailsView> runs afoul of all sorts of parsing challenges since Page is an interface, and even trying to use PageImpl isn't entirely straightforward. In the end, I don't even really care about the Page object, I just care about the nested list of POJOs inside it.
I've tried various permutations like the code below to just grab the bit I care about:
#Test
fun `extract nested`() {
val page = PageImpl(listOf(
BookDetailsView(UUID.randomUUID())
))
whenever(bookDetailsService.getBookDetailsPaged(any())).thenReturn(page)
val response = Given {
mockMvc(mockMvc)
} When {
get("/book_details")
} Then {
statusCode(HttpStatus.SC_OK)
body("content.size()", `is`(1))
body("content[0].id", equalTo(page.first().id.toString()))
} Extract {
path<List<BookDetailsView>>("content")
}
println(response[0].javaClass)
}
The final println spits out class java.util.LinkedHashMap. If instead I try to actually use the object, I get class java.util.LinkedHashMap cannot be cast to class BookDetailsView. There are lots of questions and answers related to this, and I understand it's ultimately an issue of the underlying JSON parser not knowing what to do, but I'm not clear on:
Why does the "simple" case parse without issue?
Shouldn't the type param passed to the path() function tell it what type to use?
What needs configuring to make the second case work, OR
Is there some other approach for grabbing a nested object that would make more sense?
Digging a bit into the code, it appears that the two cases may actually be using different json parsers/configurations (the former seems to stick to rest-assured JSON parsing, while the latter ends up in JsonPath's?)
I don't know kotlin but here is the thing:
path() doesn't know the Element in your List, so it'll be LinkedHashMap by default instead of BookDetailsView.class
to overcome it, you can provide TypeReference for this.
java example
List<BookDetailsView> response = ....then()
.extract().jsonPath()
.getObject("content", new TypeRef<List<BookDetailsView>>() {});
kotlin example
#Test
fun `extract nested`() {
var response = RestAssured.given().get("http://localhost:8000/req1")
.then()
.extract()
.jsonPath()
.getObject("content", object : TypeRef<List<BookDetailsView?>?>() {});
println(response)
//[{id=1}, {id=2}]
}

ServiceStack Deserialize Json (with types) to List of specific type

I have this json:
{
"$type": "System.Collections.Generic.List<MyType>",
"$values": [
{
"$type": "MyType",
"o": 7.54,
"t": 1619002800000,
"n": 3
},
{
"$type": "MyType",
"o": 7.53,
"t": 1619005140000,
"n": 3
}
]
}
I want to deserialize it back into a List<MyType>. I thought there would be an easy way to do that some thing like this:
var myList = json.FromJson<MyType>();
but that doesn't work.
I have figured out a way to accomplish my goal but it's a bit messy so I was wondering if there's a better way that I'm not aware of. Here's the messy way I came up with:
var myListOfObject = (List<object>)((Dictionary<string, object>)JSON.parse(json))["$values"];
var myTypes = myListOfObject.ConvertAll(x => JSON.stringify(x).FromJson<MyType>());
I'm not necessarily looking for fewer lines of code because 2 isn't anything to complain about. I'm just hoping there is a way that doesn't require all the casting and parsing and rather can accept the json as is and get it back to the type it came from. Maybe there's even a parameter I can set to tell it to validate types during the deserialization since the full type names are in the json.
You should use the same serializer you used to serialize the payload to deserialize it. ServiceStack.Text uses __type to embed its type information, in a different schema so you wont be able to use ServiceStack.Text to automatically deserialize it into the embedded type.
This likely used JSON.NET which you should use instead to deserialize it, otherwise yeah you can use ServiceStack's JS Utils to deserialize arbitrary JSON as you're doing.

How to set array property value in code using Carina Test Framework for API tests?

I have the following request json body:
{
...
"attachmentIds": "${attachments}"
...
}
I have a properties file that includes the declaration of the corresponding placeholder
I want to set array of strings in code instead of "attachments" placeholder, but getProperties().setProperty() expects only string value.
How can I achieve it other way or is it possible at all?
Thanks!
As an option you can transform your array into the String in java code. And then pass this String as property value.
Another option, you can pass String array from code and then parse it in your json template.
For example:
String[] arr = { "1", "2", "3" };
apiMethod.addProperty("attachments", arr);
And then in your json:
{
"attachmentIds": [<#list attachments as val>"${val}"<#if val?has_next>,</#if></#list>]
}
Check freemarker documentation to get more details:
https://freemarker.apache.org/docs/ref_builtins_loop_var.html
Also please note that some of freemarker functions (including has_next) are available only in newest versions of library. So make sure to add into your dependencies list. Carina is now in process of migrating to latest freemarker version.

C# removes duplicates in JSON request body

I've this endpoint:
[HttpPost]
[ODataRoute("some\odata\route")]
public async Task<HttpResponseMessage> Func_Name(Request_Type request)
{
...
}
request is IDictionary< string, string>. If user calls this endpoint with a JSON containing duplicates:
{
"Bob": "Doctor",
"Tim": "Engineer",
"Bob": "Sailor"
}
What I see in C# is:
{
"Tim": "Engineer",
"Bob": "Sailor"
}
Means, it always takes the last. How can I stop this automatic removal and see the duplicates after deserialization? Or making the endpoint fail on calls like these?
If you remove your parameter of your Post method you can try the following. Otherwise C# will try to automatically map the entity which will lead to an error.
var rawJson = await this.Request.Content.ReadAsStringAsync();
That will get you the raw JSON which will not be validated and hold the three properties: two of which have the "Bob" key. However I would consider this a bad idea and I'm puzzled by your use case.
C# cannot possibly convert your JSON to a Dictionary<string, string> seeing as the Key property of a Dictionary must always be unique. Needless to say that the JSON is also considered invalid when run through a validator.
{
"Bob": "Doctor",
"Tim": "Engineer",
"Bob": "Sailor"
}
I ended up switching to List instead of Dictionary

Why does storing a Nancy.DynamicDictionary in RavenDB only save the property-names and not the property-values?

I am trying to save (RavenDB build 960) the names and values of form data items passed into a Nancy Module via its built in Request.Form.
If I save a straightforward instance of a dynamic object (with test properties and values) then everything works and both the property names and values are saved. However, if I use Nancy's Request.Form then only the dynamic property names are saved.
I understand that I will have to deal with further issues to do with restoring the correct types when retrieving the dynamic data (RavenJObjects etc) but for now, I want to solve the problem of saving the dynamic names / values in the first place.
Here is the entire test request and code:
Fiddler Request (PUT)
Nancy Module
Put["/report/{name}/add"] = parameters =>
{
reportService.AddTestDynamic(Db, parameters.name, Request.Form);
return HttpStatusCode.Created;
};
Service
public void AddTestDynamic(IDocumentSession db, string name, dynamic data)
{
var testDynamic = new TestDynamic
{
Name = name,
Data = data
};
db.Store(testDynamic);
db.SaveChanges();
}
TestDynamic Class
public class TestDynamic
{
public string Name;
public dynamic Data;
}
Dynamic contents of Request.Form at runtime
Resulting RavenDB Document
{
"Name": "test",
"Data": [
"username",
"age"
]
}
Note: The type of the Request.Form is Nancy.DynamicDictionary. I think this may be the problem since it inherits from IEnumerable<string> and not the expected IEnumerable<string, object>. I think that RavenDB is enumerating the DynamicDictionary and only getting back the dynamic member-names rather than the member name / value pairs.
Can anybody tell me how or whether I can treat the Request.Form as a dynamic object with respect to saving it to RavenDB? If possible I want to avoid any hand-crafted enumeration of DynamicDictionary to build a dynamic instance so that RavenDB can serialise correctly.
Thank You
Edit 1 #Ayende
The DynamicDictionary appears to implement the GetDynamicMemberNames() method:
Taking a look at the code on GitHub reveals the following implementation:
public override IEnumerable<string> GetDynamicMemberNames()
{
return dictionary.Keys;
}
Is this what you would expect to see here?
Edit 2 #TheCodeJunkie
Thanks for the code update. To test this I have:
Created a local clone of the NancyFx/Nancy master branch from
GitHub
Added the Nancy.csproj to my solution and referenced the project
Run the same test as above
RavenDB Document from new DynamicDictionary
{
"Name": "test",
"Data": {
"$type": "Nancy.DynamicDictionary, Nancy",
"username": {},
"age": {}
}
}
You can see that the resulting document is an improvement. The DynamicDictionary type information is now being correctly picked up by RavenDB and whilst the dynamic property-names are correctly serialized, unfortunately the dynamic property-values are not.
The image below shows the new look DynamicDictionary in action. It all looks fine to me, the new Dictionary interface is clearly visible. The only thing I noticed was that the dynamic 'Results view' (as opposed to the 'Dynamic view') in the debugger, shows just the property-names and not their values. The 'Dynamic view' shows both as before (see image above).
Contents of DynamicDictionary at run time
biofractal,
The problem is the DynamicDictionary, in JSON, types can be either objects or lists ,they can't be both.
And for dynamic object serialization, we rely on the implementation of GetDynamicMemberNames() to get the properties, and I assume that is isn't there.