Serialize and Deserialize arbitrary value using Jackson - java

I have a request json in the format:
{
"key1": "value1",
"key2": "value2",
.
..
...
"keyn": "valuen",
"generic": {
"key1":"string-type-value1"
"key2":"string-type-value2"
"key3":"complex-type-value3"
.
..
...
"keyn": "simple/complex-valuen"
}
}
As we can see, there is a property called generic .This property was initially made to accept arbitrary key-value pairs in String format only. Hence,we created a property Map<String,String>
The future requirement is such that we should also be able to accept arbitrary complex type value(such as list,array,etc) and not only String.
Is there a less-complex way to serialize/deserialize for this use-case using Jackson?

This property was initially made to accept arbitrary key-value pairs in String format only. Hence, we created a property Map<String, String>. [...] we should also be able to accept arbitrary complex type value(such as list,array,etc) and not only String.
Use a Map<String, Object> instead.

Related

Convert only whitelisted properties from JSON to Map<String, Object>

Want to convert incoming JSON to a Map<String, Object> but with the following requirements:
Unknow properties should not cause exceptions (objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)).
Only whitelisted properties of the incoming JSON should appear in the Map (with the above configuration even unknown properties would be present in the Map).
The whitelisted properties should automatically correspond to the fields of a POJO.
Converting the JSON directly to my POJO would take care of points 1, 2, and 3, but I would lose the knowledge of which properties were included in the incoming JSON, that's why I want to convert to a Map.
Going from JSON to POJO to Map (let's call it Map2) would also work, but then any primitive fields in the POJO would have default values in Map2, even though they were absent in the JSON.
Put another way, I want the fields in the resultant Map to be the intersection of the properties of the JSON and the fields in the POJO.
For example, given the JSON:
{
"name": "ABCD",
"_email": "abcd#example.com",
"roles": [
"USER"
]
}
where name and roles are valid fields in the POJO (email is valid, but not _email), I want to end up with the Map:
{
name: "ABCD",
roles: [ "USER"]
}
Don't want to have to hand-code the list of valid field names for the various POJOs.

Java: get Map from Object

Using this code
Map<String,Object> payloadMap = new HashMap<String,Object>();
payloadMap = (Map<String,Object>) new Gson().fromJson(result, payloadMap.getClass());
, I convert this json:
{
"name":"name1",
"job":"prosecutor",
"department": {
"department_name":"prosecutor's office"
}
}
to the map (map with unlimited number of child maps):
This done well, but now I want to get an access to values of child (nested) maps.
In parent map child maps "wrapped" to Object.
So, I tried to get "wrapped" child maps from the Object-values of parent map.
public void mapRequestNode (Map<String,Object> payloadMap) {
payloadMap.entrySet().forEach(node->this.getDataFromNode(node));
}
As you can see from the above picture, there are no way to use child map "department", which had been "wrapped" to Object. I have an access to Object-methods, but not to the Map-methods (for example, I cant use "value.get("department_name")". I tried cast "(Map<String, Object>)value", but without success...
The "department" name in case above is only for example! I dont know concrete name of json child-objects. There may be unlimited number of names! So I cant use something like this "payloadMap.get("department")"
Following
((Map<String, Object>)payloadMap.get("department")).get("department_name")
should work, dont?
Your variable value is of type Object, which means that the compiler will not know anything else about the variable. Even if the object you retrieve from your json file is a map, as you store it in a Object variable, the compiler will handle it as an Object and not as a Map. That is why you cannot do value.get("department"); : the method get does not exist for the type Object.
You need to cast whatever is stored in value.get("department") as a Map<String, Object> to be able to handle it as a Map.
I have found a special solution.
I convert json to Map<String,Map<String,Object>>.
Not in Map<String,Object>. In this case I can successfully use child-maps of parent dto-map.
But this solution is special (not general) in the meaning that, I can handle in this way json, which consist only of objects.
For example, if I try to get the value of "job" in following example:
{
"job": "prosecutor",
"department": {
"department_name":"prosecutor's office"
}
}
by using Map.Entry<String, Map<String, Object>> payloadNodeEntry.getValue,
I will receive ClassCastException (cant cast String to Map<String, Object> ).

Jackson fasterxml pojo to map conversion with datatype

I wanted to create a cxf request object by mapping dynamic attributes to a hashmap with a key as value of the key and value as value by converting to a specific datatype which is mentioned in the type.
My request looks like
{
"id":"10001",
"name":"suresh",
"dynamicAttribute":[
{
"key":"dob",
"value":"02/05/2016",
"type":"date"
},
{
"key":"age",
"value":"27",
"type":"int"
}
]
}
Please let me know the possible ways to convert this...
First create request pojo class mapped with the json request, in which you will have array list for "dynamicAttribute". Once you get the request converted to pojo, iterate over the "dynamicAttribute" array list, inside the loop use switch statement of "type", mention all the cases for types (example - date, int, double), create object inside all cases based on the type, and put it in a Map where key will be the key string (example - dob, age) and value will be the type object.
This may not be the best solution, but you can give it a try.

How to serialize/deserialize a map with Solr/Lucene?

I am new to solr, and I am facing a problem when I try to serialize/deserialize a Map in Solr.
I use Spring Data Solr in my Java application as follow:
#Field("mapped_*")
private Map<String, String> values;
It flatten and serializes my map in Solr as follow:
"key1" : "value1"
"key2" : "value2"
...
However, when I run a search, the returned objects have this field always set as NULL. Deserialization does not work on this particular field, it looks like it does not recognize the key1, key2... as part of the Map.
Does anyone know how to make the derialization work? Do I have to implement a custom converter?
At this time Spring Data Solr does not automatically prefix values contained in the map with the given #Field#value, but will just use the Map#key as fieldname. There's an improvement (DATASOLR-202) open.
At this time having key1, key2,.. in values requires the fieldname to be key* in order to read back values correctly.
#Field("key*")
private Map<String, String> values;

Parsing JSON into Map<String, Entity> with FlexJSON

I am trying to parse a JSON structure similar to this one:
{
"cars": {
"112": {
"make": "Cadillac",
"model": "Eldorado",
"year": "1998"
},
"642": {
"make": "Cadillac",
"model": "Eldorado",
"year": "1990"
},
"9242": {
"make": "Cadillac",
"model": "Eldorado",
"year": "2001"
}
}}
I have a CarEntity class defined with makeName,model,year attributes defined and accessible via setters/getters.
I am trying to deserialize this JSON like this:
Map<String, CarEntity> deserialized = new JSONDeserializer<Map<String, CarEntity>>()
.use("cars.values", Map.class)
.deserialize(json);
and it doesn't work :( It does deserialize it but not into Map<String, CarEntity> but rather into deep Map(something like Map<String, Map<String, Map<String, String>>> )
What am I doing wrong?
You're problem is your json has two maps. One which contains the 'cars' key, and one that contains the actual CarEntity. Unfortunately, you can't refer to a single key within a Map and assign types on just that key at this time. Generally setting types on values for collections refers to all values within the collection. You don't need to specify the types for the first Map that contains the "cars" key since it will deserialize it by default.
Map<String, CarEntity> deserialized = new JSONDeserializer<Map<String,Map<String, CarEntity>>>()
.use("values.values", CarEntity.class )
.deserialize(json).get("cars");
The path 'values.values' refers to the outer Map's values then traversing the next map values are all CarEntity instances.
I've considered changing the path expressions to be more expressive allowing you to target a single value in a collection, but this increases overhead of evaluating them and being backwards compatible is a challenge.
You are most likely being bitten by Java Type Erasure: JSON library in question does not know type you want; all it sees is equivalent of Map. So you must specify at least value type somehow. Hopefully FlexJSON documentation points out how.
Alternatively you may be able to sub-class HashMap into your own type (MyEntityMap extends HashMap), since then type information can be inferred from generic super type; and passing MyEntityMap.class would give type information that most JSON libraries can use (Jackson and GSON at least).
If these do not work, Jackson and GSON libraries can handle this use case easily; both have methods to specify generic types for deserialization.
Just add one more call to get("cars") like:
Map<String, CarEntity> deserialized = new JSONDeserializer<Map<String, CarEntity>>()
.use("cars.values", Map.class)
.deserialize(json).get("cars");
jSon string was probably serialized from a variable cars typed as Map<String, CarEntity>

Categories

Resources