I'm testing a controller that returns a Map
#RequestMapping("/")
#ResponseBody
public Map<String, String> getMessages(#RequestBody String foo) {
Map<String, String> map = boo.getMap(foo);
return map;
}
Test:
...
resultActions
.andDo(print())
.andExpect(status().isOk())
.andExpect(
content().contentTypeCompatibleWith(
MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$", notNullValue()))
.andExpect(jsonPath(EXPRESSION, equalsTo(foo));
...
Which expression should I use to read the key and the value from the Map?
Edit:
A way around to solve it could be:
MvcResult result = resultActions.andReturn();
MockHttpServletResponse response = result.getResponse();
String content = response.getContentAsString();
Gson gson = new Gson();
Type typeOfT = new TypeToken<Map>() {
}.getType();
Map<String, String> map = gson.fromJson(content, typeOfT);
And then loop through the map checking the values. But is there a way to do it with jsonPath?
If you're using hamcrest Matchers that's pretty easy. There are two methods to get your hands on either key or value of the map entry.
Matchers.hasKey()
Matchers.hasValue()
And a simple example to check if all keys are present in the resulting Map. $.translationProperties directly points to the map.
ResultActions resultActions = mvc.perform(...);
List<String> languagesToBePresent = new ArrayList<>(); //add some values here
for (String language : languagesToBePresent) {
resultActions.andExpect(
jsonPath("$.translationProperties", Matchers.hasKey(language)));
}
Related
I have a JSON like this: [{key:key1, value:value1}, {key:key2, value:value2}, ..., {key:keyn, value:valuen}]
and I need a HashMap in Java from that json like: {key1:value1, key2:value2, ..., keyn:valuen}
Is there a simple way to have it converted like this? I'm trying with Jackson but don't know how to specify key and value keywords.
It is very simple:
https://stackoverflow.com/a/24012023/7137584
I would recommend using Jackson library:
import com.fasterxml.jackson.databind.ObjectMapper;
TypeReference<HashMap<String, Object>> typeRef = new TypeReference<>() {};
Map<String, Object> mapping = new ObjectMapper().readValue(jsonStr, typeRef);
The input JSON describes an array/list of map entries where each entry is a POJO:
#Data
class Entry {
private String key;
private String value; // the type of value may be Object
}
Here #Data is a Lombok annotation which provides getters, setters, toString, etc.
So, at first a list of map entries is read, which is converted then to the map:
String json = "[{\"key\":\"key1\", \"value\":\"value1\"}, {\"key\":\"key2\", \"value\":\"value2\"}, {\"key\":\"keyN\", \"value\":\"valueN\"}]";
// step 1: read raw list of entries
List<Entry> input = mapper.readValue(json, new TypeReference<List<Entry>>() {});
// step 2: convert to map
Map<String, String> mapRead = input.stream()
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
System.out.println(mapRead);
Output:
{key1=value1, key2=value2, keyN=valueN}
Here's a solution using the JSON-P api.
import javax.json.*;
var str = "[{\"key\":\"key1\", \"value\":\"value1\"}, {\"key\":\"key2\", \"value\":\"value2\"}, {\"key\":\"keyN\", \"value\":\"valueN\"}]";
JsonReader reader = Json.createReader(new StringReader(str));
JsonArray jarr = reader.readArray();
Map<String,String> map = new HashMap<>();
for(JsonValue jv : jarr) {
JsonObject jo = (JsonObject)jv;
map.put(jo.getString("key"), jo.getString("value") );
}
System.out.println(map);
I am using a JsonReader to convert the String to a JsonArray object.
Each entry of this JsonArray is a JsonObject like {key: keyX, value: valueX}.
I get the values corresponding to 'key' and 'value' and add them to a HashMap using a for loop.
This is my 1st project in java spring. So i m trying to figure out the best way to do things.
I have several Rest Apis in my project for which different kinds of API response will be sent.
Somewhere i m getting data in List Format, somewhere else another format. So i m trying to figure out the best way to send response in JSON format.
One of the API Response i have is this:
{
"result": "true",
"message": null,
"data": "{\"id\":1,\"firstName\":\"test\",\"lastName\":\"test\",\"emailId\":\"test#test.com\",\"mobileNo\":\"1234567890\",\"alternateMobileNo\":\"1234567890\",\"username\":\"test\",\"password\":\"7c4a8d09ca3762af61e59520943dc26494f8941b\",\"status\":\"active\",\"userRole\":\"test\",\"dateCreated\":\"Feb 6, 2019\",\"permissions\":\"\"}"
}
My biggest issue is the formatting of data key in the above JSON.
This is my controller action:
#RequestMapping(value = "/admin/staff/get", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public Map get(HttpServletRequest request, #RequestParam Map<String, String> parameters) {
Map<String, String> response = new HashMap<>();
Gson gson = new Gson();
Staff staff = new Staff();
staff.setId(new Integer(parameters.get("id")));
List validateToken = loginAuthTokenService.validateToken(new Integer(request.getHeader("loginId")), request.getHeader("loginType"), request.getHeader("token"));
if (validateToken.size() > 0) {
Staff staffDetails = staffService.getStaff(staff.getId());
response.put("result", "true");
response.put("data", gson.toJson(staffDetails));
} else {
response.put("result", "false");
response.put("message", "No records found.");
}
return response;
}
Should I create a separate Class for sending API Response or anyone please guide me the proper way of sending response.
Thanks
Gson#toJson(Object) returns a String and that String is mapped as JSON key in your map.
You don't have to convert your object to a JSON, Spring will do it for you (it uses Jackson as JSON mapper so you don't have add Gson dependency to your project.
A simple and working implementation could be something like:
#RequestMapping(value = "/admin/staff/get", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public ResponseEntity<?> get(
#RequestParam("id") Integer id,
#RequestHeader("loginId") Integer loginId,
#RequestHeader("loginType") String loginType,
#RequestHeader("token") String token) {
List validateToken = loginAuthTokenService.validateToken(loginId, loginType, token);
if (!validateToken.isEmpty()) {
Stuff stuff = staffService.getStaff(id);
return ResponseEntity.ok(stuff);
}
return ResponseEntity.notFound().body("No records found.");
}
Also consider to not return a generic map from your method, but the Stuff object your front-end needs. In case of failure you should return a failure object with a specific http response code (e.g. 404, 400, 500...).
Take a look at this guide.
To format the the data attribute , you can store it in a map :-
Map<String, Object> map1= new HashMap<String, Object>();
and is you have multiple data attributes you can create an ArrayList of Maps :-
ArrayList<Map<String, Object>> dataClerk = new ArrayList<Map<String,Object>>();
I had a similar usecas so i used the below code :-
obj = parser.parse(response);
JSONObject jobj = (JSONObject)parser.parse(response);
JSONArray jsonarr_1 = (JSONArray) jobj.get(item);
for(int i=0 ;i<jsonarr_1.size();i++) {
Map<String, Object> entry = new HashMap<String, Object>();
org.json.simple.JSONObject temp= (org.json.simple.JSONObject)
jsonarr_1.get(i);
Set<String> attributes= temp.keySet();
for(String s: attributes) {
entry.put(s, temp.get(s));
}
}
I want to search data from a table where Map<String,String> is passed as parameter in search method. It will also return a Map<String,String>.
I want to solve it using Spring and Hibernate.e.g:
Map<String, String> findByItem(Map<String, String> q){
}
if you can not change method signature. i think it will be below...
Map<String, String> findByItem(Map<String, String> q){
Query listQuery = session.createSQLQuery("SELECT quiestionnaireCode, questionnaireName FROM Questionnaire WHERE quiestionnaireCode =:quiestionnaireCode AND quiestionnaireName =:quiestionnaireName");
listQuery.setParameter("quiestionnaireCode", q.get("quiestionnaireCode");
listQuery.setParameter("quiestionnaireName", q.get("quiestionnaireName");
List<Questionnaire> quiestionnaireList= listQuery.list();
Gson gson = new Gson();
String str = gson.toJson(quiestionnaireList);
Map<String, String> output = new HashMap<String, String>();
output.add("result",str);
return output;
}
I use this list:
List<HashMap<Map<String, Object>, Map<String, Object>>>
And I need to save it to a text file.
So with the List#toString method, I obtain a text like that:
[{{key=value, key=value, key=value}={key=value, key=value}}, {{key=value, key=value, key=value}={key=value, key=value}}, {{key=value, key=value, key=value}={key=value, key=value}}]
How can I convert it back to a List?
Thanks!
You are better off using a format like JSON or YAML. Usng toString() means there is too many corner cases like a = { } or , appearing in a key or value.
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> map1=new HashMap<>();
map1.put("key","value");
map1.put("key1","value");
map1.put("key2","value");
map1.put("key3","value");
HashMap<Map<String, Object>, Map<String, Object>> hash=new HashMap<>();
List<HashMap<Map<String, Object>, Map<String, Object>>> lists=new ArrayList<>();
hash.put(map1, map1);
lists.add(hash);
System.out.println(mapper.writeValueAsString(lists));
The toString() method produces a format that is intended for logging and debugging, not for serialization and deserialization.
I recommend to convert your object into json format (other formats like xml can work just as well) and use a json library such as "Gson" for conversions.
Example how you can convert your object into a json string:
Gson gson = new Gson();
String json = gson.toJson(myObject);
Example how you can convert the json string back into an object, see:
creating Hashmap from a JSON String
Update: Here's a complete example of the first part:
List<HashMap<Map<String, Object>, Map<String, Object>>> myObject = new ArrayList<>();
HashMap<Map<String, Object>, Map<String, Object>> hashMap1 = new HashMap<>();
myObject.add(hashMap1);
Map<String, Object> key1 = new HashMap<>();
key1.put("key1", "keyValue1");
Map<String, Object> value1 = new HashMap<>();
value1.put("value1", "valueValue1");
hashMap1.put(key1, value1);
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
String json = gson.toJson(myObject);
System.out.println(json);
This example prints:
[{"{key1=keyValue1}":{"value1":"valueValue1"}}]
Update2 Use Pair (from apache commons lang3) instead of HashMap. That makes a lot more sense.
List<Pair<Map<String, Object>, Map<String, Object>>> myObject = new ArrayList<>();
MutablePair<Map<String, Object>, Map<String, Object>> pair1 = new MutablePair<>();
myObject.add(pair1);
Map<String, Object> key1 = new HashMap<>();
key1.put("key1", "keyValue1");
Map<String, Object> value1 = new HashMap<>();
value1.put("value1", "valueValue1");
pair1.setLeft(key1);
pair1.setRight(value1);
Gson gson = new Gson();
String json = gson.toJson(myObject);
System.out.println(json);
Prints:
[{"left":{"key1":"keyValue1"},"right":{"value1":"valueValue1"}}]
I have a JSONObject with some attributes that I want to convert into a Map<String, Object>
Is there something that I can use from the json.org or ObjectMapper?
You can use Gson() (com.google.gson) library if you find any difficulty using Jackson.
//changed yourJsonObject.toString() to yourJsonObject as suggested by Martin Meeser
HashMap<String, Object> yourHashMap = new Gson().fromJson(yourJsonObject, HashMap.class);
use Jackson (https://github.com/FasterXML/jackson) from http://json.org/
HashMap<String,Object> result =
new ObjectMapper().readValue(<JSON_OBJECT>, HashMap.class);
This is what worked for me:
public static Map<String, Object> toMap(JSONObject jsonobj) throws JSONException {
Map<String, Object> map = new HashMap<String, Object>();
Iterator<String> keys = jsonobj.keys();
while(keys.hasNext()) {
String key = keys.next();
Object value = jsonobj.get(key);
if (value instanceof JSONArray) {
value = toList((JSONArray) value);
} else if (value instanceof JSONObject) {
value = toMap((JSONObject) value);
}
map.put(key, value);
} return map;
}
public static List<Object> toList(JSONArray array) throws JSONException {
List<Object> list = new ArrayList<Object>();
for(int i = 0; i < array.length(); i++) {
Object value = array.get(i);
if (value instanceof JSONArray) {
value = toList((JSONArray) value);
}
else if (value instanceof JSONObject) {
value = toMap((JSONObject) value);
}
list.add(value);
} return list;
}
Most of this is from this question: How to convert JSONObject to new Map for all its keys using iterator java
The best way to convert it to HashMap<String, Object> is this:
HashMap<String, Object> result = new ObjectMapper().readValue(jsonString, new TypeReference<Map<String, Object>>(){}));
Note to the above solution (from A Paul):
The solution doesn't work, cause it doesn't reconstructs back a HashMap< String, Object > - instead it creates a HashMap< String, LinkedHashMap >.
Reason why is because during demarshalling, each Object (JSON marshalled as a LinkedHashMap) is used as-is, it takes 1-on-1 the LinkedHashMap (instead of converting the LinkedHashMap back to its proper Object).
If you had a HashMap< String, MyOwnObject > then proper demarshalling was possible - see following example:
ObjectMapper mapper = new ObjectMapper();
TypeFactory typeFactory = mapper.getTypeFactory();
MapType mapType = typeFactory.constructMapType(HashMap.class, String.class, MyOwnObject.class);
HashMap<String, MyOwnObject> map = mapper.readValue(new StringReader(hashTable.toString()), mapType);
The JSONObject has a method toMap which returns Map<String,Object>.
The Maven dependency used in pom.xml:
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>current-version</version>
</dependency>
You can find the current-version here.
Found out these problems can be addressed by using
ObjectMapper#convertValue(Object fromValue, Class<T> toValueType)
As a result, the origal quuestion can be solved in a 2-step converison:
Demarshall the JSON back to an object - in which the Map<String, Object> is demarshalled as a HashMap<String, LinkedHashMap>, by using bjectMapper#readValue().
Convert inner LinkedHashMaps back to proper objects
ObjectMapper mapper = new ObjectMapper();
Class clazz = (Class) Class.forName(classType);
MyOwnObject value = mapper.convertValue(value, clazz);
To prevent the 'classType' has to be known in advance, I enforced during marshalling an extra Map was added, containing <key, classNameString> pairs. So at unmarshalling time, the classType can be extracted dynamically.
This is how I did it in Kotlin:
mutableMapOf<String, Any>().apply {
jsonObj.keys().forEach { put(it, jsonObj[it]) }
}
import com.alibaba.fastjson.JSONObject;
Map<String, Object> map = new HashMap<String, Object>();
JSONObject rec = JSONObject.parseObject(<JSONString>);
map.put(rec.get("code").toString(), rec.get("value").toString());