GSON - Deserialize java generics collection - gson

I am trying to deserialize an arraylist from the DB withiout a success.
this is the way I put my objects:
for (int i = 0; i < dealsList.size(); i++) {
ServerServicesInternalWrapper.reportDeal(Json.toWrap(dealsList.get(i)));
}
where
public static <T> String toWrap(T t) {
JsonWrapperWithType wrapper =
new JsonWrapperWithType(t.getClass(),gson.toJson(t));
return to(wrapper);
}
this is the way I select
return (List<DealBean>)session.createCriteria(DealBean.class).add(Restrictions.eq("portfolio", portfolio)).list();
and then I Gson it to a string using
JsonWrapperWithType wrapper =
new JsonWrapperWithType(t.getClass(), gson.toJson(t));
return gson.toJson(wrapper );
and this is the way I de-gson the object
And now - the exception
Type listType = new TypeToken<List<DealBean>>(){}.getType();
List<DealBean> dealsForPortfolio =
(List<DealBean>)gson.fromJson(dealsForPortfolioString,type);
com.google.gson.JsonParseException: The JsonDeserializer
com.google.gson.DefaultTypeAdapters$CollectionTypeAdapter#1f899e9 failed to deserialized
json object {"type":"java.util.ArrayList","content":"[{\"ID\":5,\"tradable\":
...
Caused by: java.lang.IllegalStateException: This is not a JSON Array.

Gson expects a list of Json objects like: [{obj1}, {obj2}, ... , {objN}]
I'm not sure from code you posted here what your intentions were but it seems to me like you are wrapping a list with parent object.
In the case you want it like that, you need to make your own deserializer.

Related

Gson.toJsonTree(intValue) throws Null pointer exception when trying to pass Integer parameter value

We are automating rest APIs using Rest Assured. During this process, trying to have a re-usable method created to pass different JSON nodes with different values.
Interger variable created:
Integer amt = 50;
Method created:
public void replaceValues_gson(String mainNode, String childNode, Integer amt) {
if(amt != null){
jsonObjectNew.getAsJsonObject("mainNode").add("childNode", gson.toJsonTree(amt));
}
//here 'amt' throws an error as java.lang.NullPointerException; Also the amt it shows as 9 assigned to variable amt in the debugger where as it supposed to assign 50 value
}
Calling above method as:
replaceValues_gson("bInfo", "bEx", amt );
Request JSON payload for the above is:
{
"bInfo":{
"bEx":9,
"oriDate":"2020-07-08"
}
}
Getting NullPointerException for 'amt' variable and Request JSON payload value is getting assigned rather assigning Integer amt value which is 50.
It works if directly trying like below:
jsonObjectNew.getAsJsonObject("bInfo").add("bEx", gson.toJsonTree(amt));
here amt variable value correctly goes as 50, but when trying to create re-usable method then throws an error.
Please guide.
You can use the following method. But it does not support when the value that need to be updated is inside a json array.
public void replaceValues_gson(JsonObject jsonObjectNew, String[] keyArray, Object updatingValue) {
Gson gson = new Gson();
JsonObject jsonObject = jsonObjectNew;
for (int i = 0; i < keyArray.length - 1; i++) {
jsonObject = jsonObject.getAsJsonObject(keyArray[i]);
}
jsonObject.add(keyArray[keyArray.length - 1], gson.toJsonTree(updatingValue));
System.out.println(jsonObjectNew.toString());
}
Here;
jsonObjectNew - the JsonObject converted from initial json request.
keyArray - String array of json node names from the root (in the exact order) including the key that need to be updated
updatingValue - value that will be updated
Eg:-
String[] keyArray = {"bInfo", "bEx"};
replaceValues_gson(jsonObjectNew, keyArray, 50);

How will neo4j jdbc (bolt) handle queries that return a list of nodes?

In neo4j jdbc (bolt), Node is returned as Map , but if you make a query that returns a list of Nodes, getObject () will return a list of InternalNodes. Entities in this list can not be identified by type instanceof, so reflection will identify the node by type name and you will get the value by calling the method by reflection.You can get the value by doing the following, but is this approach correct? rs is ResultSet.entity is return value of this method.
Object columnObject = rs.getObject(columnName);
if (columnObject instanceof List<?>){
List<Map<String,Object>> objectValue = arrayList();
Array columnArray = rs.getArray(columnName);
Object[] columnArrayValues = (Object[]) columnArray.getArray();
for (int iTmp = 0; iTmp < columnArrayValues.length; iTmp++){
Map<String, Object> colArrayItemMap = new HashMap<>();
Object colItemObj = columnArrayValues[iTmp];
Class colItemClass = colItemObj.getClass();
if (colItemClass.getName().equals("org.neo4j.driver.internal.InternalNode")){
Method asMap = colItemClass.getMethod("asMap");
Method getId = colItemClass.getMethod("id");
Method getLabels = colItemClass.getMethod("labels");
colArrayItemMap.put("_id", getId.invoke(colItemObj));
colArrayItemMap.put("_labels", getLabels.invoke(colItemObj));
colArrayItemMap.putAll((Map<? extends String, ?>) asMap.invoke(colItemObj));
} else {
colArrayItemMap.put("_raw", columnArrayValues[iTmp]);
}
objectValue.add(colArrayItemMap);
}
((Map) entity).put(propertyName, objectValue);
} else {
((Map) entity).put(propertyName, columnObject);
}
Such queries are generated by such cypher statements.Such queries are generated by such cypher statements.
MATCH
(input:Input),
(output:Output)
WITH input, output
MATCH
(input)-[:INPUT*1]->(in),
(out)-[:OUTPUT*1]->(output),
g = (in)-[connect:CONNECT*0..5]->(out)
RETURN
input, output, extract(x IN nodes(g)|x) as nodes
It was for different class loaders that we can not identify with the instanceof operator.Since the jdbc driver was placed in Tomcat / lib, it was judged to be different from the class loaded by the application.
In any case, it will be provided by converting List to List or until getResults() is supported as the return value of getArray() It is thought that it is necessary to write.

Castle Core Invocation create a cache key from intercepted method

I'm using a interface interceptor to cache all methods that starts with "Get" but i can't figure out how to generate a unique cache key for every unknown parameter it can be anything and using GetHashCode is not an option as i can't be 100% sure that they have overridden the GetHashCode.
some thoughts was someting in the line of How can I create a unique hashcode for a JObject?
where JSON is used for a JObject i was thinking on JSON serialize every parameter then get the hash code like explained in the link above:
var obj = JToken.Parse(jsonString);
var comparer = new JTokenEqualityComparer();
var hashCode = comparer.GetHashCode(obj);
However i think this will be a performence hit so how can this be solved ?
The code i have so far is this but it wont handle the complex type situation where .ToString won't generate the raw value type like int, string etc.
private string CreateCacheKey(IInvocation invocation)
{
string className = invocation.TargetType.FullName;
string methodName = invocation.Method.Name;
var builder = new StringBuilder(100);
builder.Append(className);
builder.Append(".");
builder.Append(methodName);
for (int i = 0; i < invocation.Arguments.Length; i++)
{
var argument = invocation.Arguments[i];
var argumentValue = invocation.GetArgumentValue(i);
builder.Append("_");
builder.Append(argument);
if (argument != argumentValue)
{
builder.Append(argumentValue);
}
}
return string.Format("{0}-{1}", this.provider.CacheKey, builder);
}
I ended up using GetHashCode as it is the only viable solution if thay dont override the method it will not cache.

Json.Net for serializing an object graph

I was using the .Net built in JavaScriptSerializer() to Serialize a JSON string coming from a webpage.
I heard that Newtonsoft.Json.Net have a better serializer, so I thought I would give it a try.
I load my json string, here is a sample.
jsonString = "{\"jName\":\"MB-CEF3-4\",\"StartDate\":\"08/20/2013 00:00\",\"EndDate\":\"08/29/2013 00:00\",\"JType\":\"General\",\"SetupParams\":[
{\"Name\":\"PTitle\",\"Title\":\"01. Period Title\",\"Type\":\"text\",\"Value\":\"TestName\"},
{\"Name\":\"PStart\",\"Title\":\"02. Period Start\",\"Type\":\"datetime\",\"Value\":\"08/20/2013\"},
{\"Name\":\"Target\",\"Title\":\"03. Target\",\"Type\":\"int\",\"Value\":\"1\"},
{\"Name\":\"URL\",\"Title\":\"04. Completion Report URL\",\"Type\":\"url\",\"Value\":\"http://www.example.com\"},
{\"Name\":\"FormTitle\",\"Title\":\"05. Form Title\",\"Type\":\"text\",\"Value\":\"ct\"},
{\"Name\":\"nvTypes\",\"Title\":\"{B6E71787-EB51-45CF-B408-552F79AF2E7B}\",\"Type\":\"nvc\",\"Value\":\"Use of nv tools\"}, {\"Name\":\"NVCoachingTypes\",\"Title\":\"\",\"Type\":\"nvc\",\"Value\":\"\"}]}";
JavaScriptSerializer scs = new JavaScriptSerializer();
Dictionary<String, Object> aps = (Dictionary<String, Object>)scs.DeserializeObject(ActSetupConfigs);
I then would pass this Dictionary into another worker class, where it is deserialized..
I was using: var parameters = ((object[])Parameters["SetupParams"]);
and it would load the an array of objects.
I tried to do the same with Json.Net
Dictionary<String, Object> aps = JsonConvert.DeserializeObject<Dictionary<String, Object>>(ActSetupConfigs);
but when I try to deserialize it I don't get an array of objects, instead the sub collection of the array is just a string....so it throws an exception. How can I use Json.net to serialize all the sub-collections?
The sub-collection of the SetupParams array is not a string, it is a JToken, which is a generic container object that JSON.Net uses to hold a JSON structure. Fortunately, it is easy to extract values from a JToken. Try using this code instead.
JToken aps = JToken.Parse(jsonString);
foreach (JToken param in aps["SetupParams"])
{
Console.WriteLine("Name: " + param["Name"].Value<string>());
Console.WriteLine("Title: " + param["Title"].Value<string>());
Console.WriteLine("Type: " + param["Type"].Value<string>());
Console.WriteLine("Value: " + param["Value"].Value<string>());
Console.WriteLine();
}
You can parse the above json response using json.net like,
dynamic initialresp=JValue.Parse(jsonString);
string jname=Convert.ToString(initialresp.jname);
...
...
dynamic setupparams=JArray.Parse(Convert.ToString(initialresp.SetupParams));
foreach(var item in setupparams)
{
string name=Convert.Tostring(item.Name);
string title=Convert.Tostring(item.Title);
...
...
}
Hope this helps.

XmlReader.ReadContentAsObject always returns string type

According to the MSDN documentation, XMLWriter.WriteValue writes xsd type information to the xml for simple CLR types. Then XMLReader.ReadContentAsObject supposedly reads out the appropriately-typed object when the XML is parsed. However, this always seems to return a string object for me and the ValueType property of the XMLReader is string. I've tried inserting longs and DateTimes, but they always end up as strings. Any ideas what I'm doing wrong or is this a Windows Phone bug?
XML Writing Code
public void WriteXml(XmlWriter writer) {
// KeyValuePair<string, object> pair initialized previously
writer.WriteStartElement(pair.Key);
writer.WriteValue(pair.Value)
writer.WriteEndElement();
}
XML Parsing Code
public void ReadXml(XMLReader reader) {
while (reader.Read()) {
if (reader.NodeType == XmlNodeType.Element) {
Type T = reader.ValueType; // T is string
reader.ReadStartElement();
object o = reader.ReadContentAsObject(); // o is string
o = reader.ReadContentAs(T, null); // o is string
}
}
}
You need to use a schema file (XSD) so that the framework can infer the type of a node. Otherwise ValueType will always return System.String.
MSDN says:
If a validation error occurs while parsing the content and the reader is an XmlReader object created by the Create method, the reader returns the content as a string. In other words when a validation error or warning occurs, the content is considered to be untyped.
I was making this too difficult. My goal was to serialize a Dictionary with generic type (string, object) by traversing its KeyValuePairs , but that class doesn't seem to be serializeable using XmlSerializer. I just created another class with two public properties, Key and Value, so I could use XmlSerializer. When deserializing with XmlSerializer, the type of Value is restored as long as it is a supported CLR type.
public void WriteXml(XmlWriter writer) {
// KeyValuePair<string, object> pair initialized previously
writer.WriteStartElement("entry");
MyClass toSerialize = new MyClass(pair.Key, pair.Value);
XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
serializer.Serialize(writer, toSerialize);
writer.WriteEndElement();
}

Resources