My app does HTTP requests using this GsonRequest implementation.
Some of the requests parameters are not simple string keys and string values, but some values can be a map too.
For instance:
{
"Key1" : "value",
"Key2" : {
"Key2.1" : "value",
"Key2.2" : "value",
"Key2.2" : "value"
},
"Key3" : "value"
}
The JSON parameters above can be built using HashMaps like this:
Map<String, String> subMap = new HashMap<String, String>();
subMap.put("Key2.1", "value");
subMap.put("Key2.2", "value");
subMap.put("Key2.3", "value");
Map<String, String> map = new HashMap<String, String>();
map.put("Key1", "value");
map.put("Key2", subMap.toString());
map.put("Key3", "value");
And then I call GsonRequest and pass map.
However, when the request is made, the JSON sent is actually:
{
"Key1" : "value",
"Key2" : "{Key2.1 = value, Key2.2 = value, Key2.2 = value}", <-- This is wrong
"Key3" : "value"
}
I tried to nest the maps using a JSONObject, with no success:
map.put("Key2.2", new JSONObject(subMap).toString());
will produce the JSON:
...
"Key2" : "{\"Key2.1\" : \"value\", \"Key2.2\" : \"value\", \"Key2.2\" : \"value\"}",
...
This one looks better, if I could escape the slashes it'd be right, but no.
How can I nest the maps properly and get the JSON correctly?
After thinking for a while, I realized that nesting Strings was wrong and that should not be used. But I was using that because the class Request, which my GsonRequest extends, requires a HashMap<String, String> map for the parameters.
What I did was to force the passage of a HashMap<String, Object> map. I didn't expected it to work, but I needed to give it a try. And it did work.
Related
I have spent a few days googling this various ways and don't see any that give examples of using HashMap - instead they all refer to Jackson or GSON. I am not able to use these as they cause an issue in Jenkins that will not be addressed (basically everything is super locked down and the work place will not "open" up alternatives)
I have a JSON body that I am attempting to send to a create record API.
For simple JSON body the process is pretty straightforward:
Desired JSON:
{
"owner": {
"firstName": "Steve",
"lastName": "Guy",
"Hair": "brown",
"Eyes": "yes"
"etc": "etc"
},
"somethingElse": "sure"
}
would look like
Map<String,Object> jsonRequest = new HashMap<>();
Map<String,String> ownerMap = new HashMap<>();
HashMap<Object, String> OwnerMap = new HashMap<Object, String>;
OwnerMap.put("firstName","Steve");
OwnerMap.put("lastName","Guy");
OwnerMap.put("Hair","brown");
OwnerMap.put("Eyes","yes");
OwnerMap.put("etc","etc");
jsonRequest.put("owner", OwnerMap);
jsonRequest.put("somethingElse", "sure");
Easy enough
If the JSON gets slightly more complex, I can't seem to figure it out.. and again I cannot use any other dependency for this.
so if I have a JSON Body that I need to send :
{
"customer": {
"address": [
{
"address": "Blah"
}
]
},
"anotherThing": "thing"
}
the same pattern does not work.
Map<String,Object> jsonRequest = new HashMap<>();
Map<String,String> ownerMap = new HashMap<>();
HashMap<Object, String> addressMap = new HashMap<Object, String>;
addressmap.put("address","Blah");
jsonRequest.put("address", addressMap);
jsonRequest.put("owner", OwnerMap);
jsonRequest.put("anotherThing", "thing");
returns as:
{
"owner": {
},
"anotherThing": "thing",
"address": {
"address": "Blah"
}
}
You seem to assume that the inner (for want of a better word) Maps need to be Map<*, String>, and that Map and String are the only things which extend Object.
Something like the following should work fine:
Map<String, Object> json = new HashMap<>();
Map<String, Object> customer = new HashMap<>();
// Could make this a Map<String, Object>[] (array) depending
// on json library used... You don't specify.
List<Map<String, Object>> address = new ArrayList<>();
Map<String, Object> innerAddress = new HashMap<>();
innerAddress.put("address", "Blah");
address.add(innerAddress);
customer.put("address", address);
json.put("customer", customer);
json.put("anotherThing", "thing");
I have a service from where I get a json string response like as shown below
{
"id": "123",
"name": "John"
}
I consume the rest call using HttpClient and converts the json string to Map<String, String> like as shown below.
String url= "http://www.mocky.io/v2/5979c2f5110000f4029edc93";
HttpClient client = HttpClientBuilder.create().build();
HttpGet httpGet = new HttpGet(url);
httpGet.setHeader("Content-Type", "application/json");
HttpResponse httpresponse = client.execute(httpGet);
String response = EntityUtils.toString(httpresponse.getEntity());
ObjectMapper mapper = new ObjectMapper();
Map<String, String> map = mapper.readValue(response, new TypeReference<Map<String, String>>(){});
The conversion from json string to HashMap is working fine, but actually my requirement was sometimes there can be some nested json within the main json, for example in the below json I am having an additional address key which is again a nested json having city and town details.
{
"id": "123",
"name": "John",
"address": {
"city": "Chennai",
"town": "Guindy"
}
}
If any nested json comes I need the make the json like as shown below
{
"id": "123",
"name": "John",
"address.city": "Chennai",
"address.town": "Guindy"
}
Currently I am using jackson library, but open to any other library which will give me this feature out of box
Can anyone help me by giving some suggestion on this.
Here is a recursive method that will flatten a nested Map with any depth to the desired dot notation. You can pass it to Jackson's ObjectMapper to get the desired json output:
#SuppressWarnings("unchecked")
public static Map<String, String> flatMap(String parentKey, Map<String, Object> nestedMap)
{
Map<String, String> flatMap = new HashMap<>();
String prefixKey = parentKey != null ? parentKey + "." : "";
for (Map.Entry<String, Object> entry : nestedMap.entrySet()) {
if (entry.getValue() instanceof String) {
flatMap.put(prefixKey + entry.getKey(), (String)entry.getValue());
}
if (entry.getValue() instanceof Map) {
flatMap.putAll(flatMap(prefixKey + entry.getKey(), (Map<String, Object>)entry.getValue()));
}
}
return flatMap;
}
Usage:
mapper.writeValue(System.out, flatMap(null, nestedMap));
I'm getting this error when attempting to parse some JSON previously generated with Jackson. I generate the JSON like so
String ret = "";
ret = mapper.writeValueAsString(message.getPayload());
message.setPayload(ret);
Where message.getPayload() is a HashMap, in this instance containing two strings and a List of various objects. This creates the following malformed JSON
{
"user" : "john d example",
"items" : [ {
"val" : 99.5,
"id" : "phone",
"qty" : 1
}, {
"val" : 15.5,
"id" : "wine",
"qty" : 4
} ],
"address" : "123 example street"
}
Which throws an exception when examined thusly
Map<String, Object> ret = new HashMap<String, Object>();
String s = (String)message.getPayload();
ret = mapper.readValue(s, new TypeReference<Map<String, String>>(){});
How should I properly write this Map to JSON?
TypeReference<Map<String, String>> should be TypeReference<Map<String, Object>>. Jackson is attempting to parse the values as Strings rather than Lists because that is what it expects based on the TypeReference you passed in.
I have JSON string with dynamic elements, till now I parse it into Map:
Map map = new Gson().fromJson(jsonString,
new TypeToken<HashMap<String, String>>() {}.getType());
Now I need to solve thsi situation - one of these dynamic variables could be another JSON string.
Do you have some advice ho to solve it? Thanks in advance.
EDIT: JSON string example added (formatted):
{
"key1": "val1",
"key2": "val2",
"key3": {
"subkey1": [
"subvalue1",
"subvalue1"
],
"subkey2": [
"subvalue2"
]
},
"key4": "val3"
}
What you call another JSON string is just a json object. Change the Map value type to Object from String: TypeToken>
String jsonString = "{\"key1\":\"val1\",\"key2\":\"val2\",\"key3\": {\"subkey1\":\"subvalue1\",\"subkey2\":\"subvalue2\"},\"key4\":\"val3\"}";
Map<String, Object> map = new Gson().fromJson(jsonString, new TypeToken<Map<String, Object>>() {
}.getType());
The above example works with GSON 2.2.2. And sysout(map) produces
{key1=val1, key2=val2, key3={subkey1=subvalue1, subkey2=subvalue2}, key4=val3}
As a small improvement I'd suggest that you explicitly specify map type parameters, and use Map instead of HashMap for the TypeToken.
I am using DWR in my project for AJAX calls. DWR converts javascript objects to java objects by reading the java class. I want to send and receive JSON like structure through DWR.
Eg:
JS Object:
{
"name" : "TamilVendhan",
"age" : "24",
"hobbies" : [
"gaming",
"gaming",
"gaming"
],
"address" : {
"doorNo" : "122",
"city" : "Banglore",
"state" : "Karnataka",
"country" : "india"
}
}
The above js object could be converted to Java as below :
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", "TamilVendhan");
map.put("age", "24");
List<String> list = new ArrayList<String>();
list.add("gaming");
list.add("gaming");
list.add("gaming");
map.put("hobbies", list);
Map<String, Object> addr = new HashMap<String, Object>();
addr.put("doorNo",122);
addr.put("city", "banglore");
addr.put("state", "Karnataka");
addr.put("country", "India");
map.put("address", addr);
Is this possible with DWR. If possible, give me some pointers!
Thanks!
Update:
Converting JS objects into Map<String, Object> is possible in DWR. But its one(1st) level only. If you have any nested objects/array, it will not be converted and ends in conversion error.
See this ticket.
The latest version of DWR has json support, you need to enable in your web.xml by passing init-param for the DWR Servlet, more information can be found at, also for DWR there is a nice Book named 'DWR Java AJAX Applications'.