I am using GSON to serialize Java object.
I have a Java class with following properties.
String property1;
Map<String, HashMap> property2 = new HashMap<>();
Map<String, ArrayList<String>> property3 = new HashMap<>();
Map<String, String[]> property4 = new HashMap<>();
I want to convert this to Json. Because of the maps with HashMaps inside, it has become difficult. I know I can get Json of a map with gsonObject.toJson(map). But I want all these properties in the Json Object. (all in one. not Concatenating many objects)
Can anyone help me to get this done?
I don't see what the problem is. Gson can serialize Maps just fine.
Assuming your class is named Test
Test test = new Test();
test.property1 = "some value";
HashMap<String, Integer> map = new HashMap<>();
map.put("one", 1);
map.put("fourty two", 42);
test.property2.put("property2-key", map);
ArrayList<String> strings = new ArrayList<>(Arrays.asList("string1",
"string2", "string3"));
test.property3.put("property3-key", strings);
String[] stringArray = { "array1", "array2", "array3" };
test.property4.put("property4-key", stringArray);
Gson gson = new Gson();
String json = gson.toJson(test);
System.out.println(json);
It generates the following
{
"property1": "some value",
"property2": {
"property2-key": {
"fourty two": 42,
"one": 1
}
},
"property3": {
"property3-key": [
"string1",
"string2",
"string3"
]
},
"property4": {
"property4-key": [
"array1",
"array2",
"array3"
]
}
}
Related
I have a JSON object that is dynamically defined.
{
"lvars": {
"task1": {
"assigned" : true,
"params": {//any key value maps here}, {//any key value maps}
},
"task2": {
"assigned" : false,
"params": {//any key value maps here}, {//any key value maps}
....
},
"mvars": {
"Id": {
"type": "String",
"value": ""
},
}
}
Now in java when I am deserializing it into code it becomes somewhat like this,
Map<String, Map<String, Map<String, Map<String, Map<String, Object>>>>> m = ObjectMapper
.fromJson(getValues(), new TypeReference<>() {});
In this case "lvars" and "mvars" are fixed keys and evrything else is variable. How can I avoid the nested map of maps declaration in Java.
Just do:
Map<String,Object> data = ObjectMapper.fromJson(getValues(), new TypeReference<>() {});
Map<String, Map<String, Map<String,Object>>> dynamic_map_0 = (Map<String, Map<String, Map<String, Object>>>) data.get("lvars");
Map<String, Map<String, Map<String,Object>>> dynamic_map_1 = (Map<String, Map<String, Map<String, Object>>>) data.get("mvars");
or simpler:
JSONObject obj = new JSONObject(inputAsString);
JSONObject dynamic0 = obj.getJSONObject("lvars");
JSONObject dynamic1 = obj.getJSONObject("mvars");
You can create a class called NestedMap which is a data structure that contains references to other NestedMap objects, like so:
class NestedMap<K, Object> {
Map<K, NestedMap<K>> data;
Object object; // object to resort to if reached the end of "map-chain"
...
}
This makes the nesting a bit less messy.
List<Map<String, List<Map<String, Object>>>> ListMapTermMapList = new ArrayList<Map<String,List<Map<String ,Object>>>>();
Input
[
{
Inventories=
[
{FINANCIAL_BLOCK=Balance Sheet, COUNTRY_ID=8, TAXONOMY_ID=34, VALUE=279.7, COMPANY_STAGING_ID=9433, FINANCIAL_NAME=Inventories, COMPANY_CODE=LENZ, TYPE=companyFinal, COMPANY_ID=31, REPORTED_IN_FINANCIALS=Inventories, SUB_BLOCK=Current Assets, _version_=1559400052581990400}, {FINANCIAL_BLOCK=Balance Sheet, COUNTRY_ID=1, TAXONOMY_ID=34, VALUE=1122.0, COMPANY_STAGING_ID=102049, FINANCIAL_NAME=Inventories, COMPANY_CODE=APPLE, TYPE=companyFinal, COMPANY_ID=2, REPORTED_IN_FINANCIALS=Inventories, SUB_BLOCK=Current Assets, _version_=1559400052590379009}
]
},
{
High Performance Mixed Signal ( HPMS )=
[
{FINANCIAL_BLOCK=Income Statement, EXTENSION_NAME=Work performed by the Group and capitalized, COUNTRY_ID=8, TAXONOMY_ID=17602, VALUE=7.5, COMPANY_STAGING_ID=9564, FINANCIAL_NAME=Other Operating Income, COMPANY_CODE=LENZ, TYPE=companyFinal, COMPANY_ID=31, REPORTED_IN_FINANCIALS=Work performed by the Group and capitalized, SUB_BLOCK=Operating Block, _version_=1559400052606107648}, {FINANCIAL_BLOCK=Income Statement, EXTENSION_NAME=Work performed by the Group and capitalized, COUNTRY_ID=8, TAXONOMY_ID=17602, VALUE=30269.0, COMPANY_STAGING_ID=8926, FINANCIAL_NAME=Other Operating Income, COMPANY_CODE=LENZ, TYPE=companyFinal, COMPANY_ID=31, REPORTED_IN_FINANCIALS=Work performed by the Group and capitalized, SUB_BLOCK=Operating Block, _version_=1559400052663779330}
]
}
]
I am trying to convert this complex nested list of map into JSON object using jackson mapper.
createJson(map);
The function for conversion is:
public static String createJson(Object obj) throws JsonGenerationException,JsonMappingException, IOException
{
org.codehaus.jackson.map.ObjectMapper mapper = new org.codehaus.jackson.map.ObjectMapper();
SimpleDateFormat sdf = new SimpleDateFormat(DF);
mapper.getSerializationConfig().setDateFormat(sdf);
String json = mapper.writeValueAsString(obj);
return json;
}
Exception
org.codehaus.jackson.map.JsonMappingException: (was
java.lang.UnsupportedOperationException) (through reference chain:
java.util.ArrayList[0]->java.util.HashMap["Inventories"]->java.util.ArrayList[0])
I think Gson will save your life in this case :
Check this example of how to use it :
public static void main(String[] args)
{
//Part 1
Map<String ,Object> map1 = new HashMap<>();
map1.put("FINANCIAL_BLOCK", "Balance Sheet");
map1.put("COUNTRY_ID", 8);
List<Map<String ,Object>> inventoriesList = new ArrayList<>();
inventoriesList.add(map1);
Map<String,List< Map<String ,Object> > > inventoriesMap = new HashMap<>();
inventoriesMap.put("Inventories", inventoriesList);
//Part 2
Map<String ,Object> map2 = new HashMap<>();
map2.put("FINANCIAL_BLOCK", "Income Statement");
map2.put("COUNTRY_ID", 8);
List<Map<String ,Object>> highPerformanceList = new ArrayList<>();
highPerformanceList.add(map2);
Map<String,List< Map<String ,Object> > > highPerformanceMap = new HashMap<>();
highPerformanceMap.put("High Performance Mixed Signal ( HPMS )", highPerformanceList);
//Collect
List<Map<String, List<Map<String, Object>>>> ListMapTermMapList = new ArrayList< Map<String,List< Map<String ,Object> > > >();
ListMapTermMapList.add(inventoriesMap);
ListMapTermMapList.add(highPerformanceMap);
//Format to Json
System.out.println(new Gson().toJson(ListMapTermMapList));
}
Output :
[
{
"Inventories": [
{
"FINANCIAL_BLOCK": "Balance Sheet",
"COUNTRY_ID": 8
}
]
},
{
"High Performance Mixed Signal ( HPMS )": [
{
"FINANCIAL_BLOCK": "Income Statement",
"COUNTRY_ID": 8
}
]
}
]
I have a json response like this
{
"queryPath": "/api/",
"nId": "f084f5ad24fcfaa9e9faea0",
"statusCode": 707
"statusMessage": "Success",
"results": {
"data": [
{
"id": "10248522500798",
"capabilities": [
"men",
"women"
],
"name": "errt2"
},
{
"id": "418143778",
"capabilities": [
"dog",
"cat"
],
"name": "Livin"
}
]
}
}
Here am adding results.data to a list as follows
private List<HashMap<String, String>> episodes = new ArrayList<HashMap<String, String>>();
episodes =helper.getJSONValue(response, "results.data");
public <T>T getJSONValue(Response res, String path ){
String json = res.asString();
JsonPath jpath = new JsonPath(json);
return jpath.get(path);
}
so episodes contains all data i mean all results.data
While i debuging am getting this way
[{id=10248522500798, name=errt2, capabilities=[men, women]}, {id=418143778, name=Livin, capabilities=[dog, cat]}]
Here i have capabilities [men, women] and [dog, cat].i need to check capability contains men or dog.
How can i do that?
If i were you i haven't done this..
Use gson and map your json into a java model. It's way better. Afterwards you can access all your model parts with getters and setters.
MyType target2 = gson.fromJson(json, MyType.class); // deserializes json into target2
As you see it's very simple :)
But if you want to iterate a list that contains a map you can use code block below:
List<Map<String, String>> test = new ArrayList<Map<String, String>>();
for( Map<String, String> map : test ){
for( Entry<String, String> entry : map.entrySet() ){
System.out.println( entry.getKey() + " : " + entry.getValue() );
}
}
With the code above you can get all the entry's keys and values and check them.
Edit:
You have to change your List to List<Map<String,Object>> after that:
List<Map<String, Object>> test = new ArrayList<Map<String, Object>>();
for( Map<String, Object> map : test ){
for( Entry<String, Object> entry : map.entrySet() ){
if( entry.getKey().equalsIgnoreCase( "capabilities" ) ){
List<String> myCapabilities = ( List )entry.getValue();
if( myCapabilities.contains( "dog" ) && myCapabilities.contains( "cat" ) ){
// BLA BLA
}
}
}
}
It's a nasty way.. I recommend you to use gson..
I am creating an application which it will send http request to a web server. The return will be in json. Here is how the json look like
[//I used a tool to make it beautiful and easy to read.
{
"item_name": "Adame",
"item_type": "Special",
"item": "Chestplate",
"item_min_lvl": "50",
"enchantment": {
"health": "0.3",
"dam": "24%",
"life": "0.1",
"xp": "24%",
"loot": "22%"
},
"def": "73"
},
{
"item_name": "Sticks'",
"item_type": "Unique",
"item": "Stick",
"item_min_lvl": "4",
"enchantment": {
"health": "0.6",
"mana": "1",
"dam": "12%",
"life": "0.3",
"xp": "17%",
"loot": "17%"
},
"min_dam": "39",
"max_dam": "34"
},
{
"item_name": "Sword'",
"item_type": "Unique",
"item": "Sword",
"item_min_lvl": "8",
"enchantment": [], //colonm 30 is [
"min_dam": "9",
"max_dam": "10"
}
]
Are you can see, the data inside the array are different. I got this error, Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 30. This is my code:
MyJSON[] data = gson.from(jsonString, MyJSON[].class);
class MyJSON {
String item_name;
String item_type;
String item;
String item_min_lvl;
Enchantment enchantment;
String min_dam;
String max_dam;
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("\nitem_name:").append(item_name);
builder.append("\nitem_type:").append(item_type);
builder.append("\nitem:").append(item);
builder.append("\nitem_min_lvl:").append(item_min_lvl);
builder.append("\n\nEnchantment Details:");
builder.append("\nhealth:").append(enchantment.health);
builder.append("\ndam:").append(enchantment.dam);
builder.append("\nlife:").append(enchantment.life);
builder.append("\nxp:").append(enchantment.xp);
builder.append("\nloot:").append(enchantment.loot);
return builder.toString();
}
}
class Enchantment {
String health;
String dam;
String life;
String xp;
String loot;
String mana;
}
Can anyone help me to improve my code so my code an parse the json in different case. Thanks in advanced. (P.s. that's not my web server so I can't do anything with the json)
Basically this line of JSON
"enchantment": [], //colonm 30 is [
doesn't match your POJO. You're expecting an Enchantment object, but the JSON is giving you an array. Fix your JSON to return an empty JSON object or nothing at all for the enchantment pair.
"enchantment": {}
This is a Valid JSON unless you have added comments just to show lines where is the issue?
Comments should not be part of JSON.
Here is the code that I have already shared you at you another post Java - Json deserialize data [].
You have to use ArrayList<Map<String, Object>> because the entries in the JSON string are not symmetric. You can't convert it into POJO in this case.
StringBuilder builder = new StringBuilder();
BufferedReader reader = new BufferedReader(new FileReader(new File("resources/json2.txt")));
String line = null;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
reader.close();
Gson gson = new Gson();
Type listType = new TypeToken<ArrayList<Map<String, Object>>>() {
}.getType();
ArrayList<Map<String, Object>> list = gson.fromJson(builder.toString(), listType);
for (Map<String, Object> json : list) {
for (String key : json.keySet()) {
System.out.println(key + ":" + json.get(key));
}
System.out.println("===========");
}
output:
item_name:Adame
item_type:Special
item:Chestplate
item_min_lvl:50
enchantment:{health=0.3, dam=24%, life=0.1, xp=24%, loot=22%}
def:73
===========
item_name:Sticks'
item_type:Unique
item:Stick
item_min_lvl:4
enchantment:{health=0.6, mana=1, dam=12%, life=0.3, xp=17%, loot=17%}
min_dam:39
max_dam:34
===========
item_name:Sword'
item_type:Unique
item:Sword
item_min_lvl:8
enchantment:[]
min_dam:9
max_dam:10
===========
EDIT
enchantment return something like
enchantment:{health=0.6, mana=1, dam=12%, life=0.3, xp=17%, loot=17%}.
How can I get for example health?
Type mapType = new TypeToken<Map<String, String>>() {
}.getType();
String string = "{health=0.6, mana=1, dam=12%, life=0.3, xp=17%, loot=17%}";
Map<String, String> map = new Gson().fromJson(string, mapType);
for (String key : map.keySet()) {
System.out.println(key + ":" + map.get(key));
}
output:
health:0.6
mana:1
dam:12%
life:0.3
xp:17%
loot:17%
You can create a custom list type in Gson's fromJson() method to map it to a list of POJOs
Type listType = new TypeToken<ArrayList<Enhancement>>() {}.getType();
List<Enhancement> enhancements = new Gson().fromJson(jsonString, listType);
You will get a List<Enhancement>.
I would like to use this kind of Objects with json:
class Message{
int code;
String user;
Map<List<String>, List<String>> profile;
}
it seems json can't handle Object keys as array, so I would need to tranfer them like that:
{
"code": 1,
"user": "John",
"profile": {
"type,1": ["tester"],
"lang,2": ["fr", "it", "en", "sp"],
"rate,4": ["10", "1000"],
"date,5": ["134118329", "1341973211"]
}
}
or
{
"code": 1,
"user": "John",
"profile": {
"type": [1,"tester"],
"lang": [2,"fr", "it", "en", "sp"],
"rate": [4,"10", "1000"],
"date": [5,"134118329", "1341973211"]
}
}
the first json is probably simpler, even if it relies on a hard string separator,
So with the first one it seems I have to write this huge adapter:
private static class MyAdapter implements JsonSerializer<Map<List<String>, List<String>>>,
JsonDeserializer<Map<List<String>, List<String>>> {
#Override
public JsonElement serialize(Map<List<String>, List<String>> m,
Type type, JsonSerializationContext context) {
JsonObject j = new JsonObject();
for (Entry<List<String>, List<String>> e : m.entrySet() ){
JsonArray jj=new JsonArray();
for (String s : e.getValue()){
jj.add(new JsonPrimitive(s));
}
j.add(e.getKey().get(0)+","+e.getKey().get(1), jj);
}
return j;
}
#Override
public Map<List<String>, List<String>> deserialize(JsonElement json, Type type,
JsonDeserializationContext arg2) throws JsonParseException {
Map<List<String>, List<String>> m = new HashMap<List<String>, List<String>>();
JsonObject jObject = json.getAsJsonObject();
for (Entry<String, JsonElement> e : jObject.entrySet() ){
List<String> key = new ArrayList<String>();
List<String> value = new ArrayList<String>();
for (String s : e.getKey().split(",") ){
key.add(s);
}
for (JsonElement jj : e.getValue().getAsJsonArray() ){
value.add(jj.getAsString());
}
m.put(key, value);
}
return m;
}
}
...
GsonBuilder g = new GsonBuilder();
g.registerTypeAdapter(Map.class, new MyAdapter());
Gson gson = g.create();
Is there faster ways? I guess yes, the idea is just to split the key into a Map composite key, because each part of the key has an important meaning
thx, and sry for the edit
This will not work.
Object declaration syntax according specification:
An object is an unordered set of name/value pairs. An object begins
with { (left brace) and ends with } (right brace). Each name is
followed by : (colon) and the name/value pairs are separated by ,
(comma).
This:
{
["type", 1]: "tester",
["lang", 2]: ["fr", "it", "en", "sp"],
["rate", 4]: ["10", "1000"],
["date", 5]: ["134118329", "1341973211"]
}
is invalid, and therefore you can't read with Gson causing the following exception: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING
the name in front of json: aRequest = is invalid too.
For profile values, I don't know if there is better than Object unfortunately
It looks like a List<String> or String[] would be a natural fit, with special handling for the single value entry that is not in a list format.
Unfortunately, the issue of deserializing a JSON structure that is sometimes a list and sometimes an object has come up repeatedly on SO. Fortunately, so have solutions.