I'm using guava to compare two JSON files together and have done the following:
ObjectMapper mapper = new ObjectMapper();
TypeReference<HashMap<String, Object>> type =
new TypeReference<HashMap<String, Object>>() {};
Map<String, Object> leftMap = mapper.readValue(leftJson, type);
Map<String, Object> rightMap = mapper.readValue(rightJson, type);
MapDifference<String, Object> difference = Maps.difference(leftMap, rightMap);
System.out.println(difference.entriesDiffering());
Output
package=([{Name=Sarah}], [{Name=Conor}])
Expected output
package=([{Name=Conor}])
Does anyone know how to manipulate the output to just show one side?
I assume that you want to end up with another Map<String,Object>, but taking the value of keys with differing values from the right (or maybe the left, you don't say).
import com.google.common.collect.MapDifference;
import com.google.common.collect.Maps;
import java.util.Map;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
Map<String, Object> left = Map.of("name", "sarah");
Map<String, Object> right = Map.of("name", "connor");
MapDifference<String, Object> result = Maps.difference(left, right);
Map<String,Object> f = result.entriesDiffering().entrySet().stream()
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().rightValue()));
System.out.println(f);
}
}
MapDifference#entriesDiffering() returns Map<K,​MapDifference.ValueDifference<V>>, so please read ValueDifference and make use of its API.
Here's a sample MRE:
#Test
public void shouldShowDifferences() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
TypeReference<HashMap<String, Object>> type =
new TypeReference<HashMap<String, Object>>() {};
String leftJson = "{\"package\": [{\"Name\": \"Sarah\"}]}";
String rightJson = "{\"package\": [{\"Name\": \"Connor\"}]}";
Map<String, Object> leftMap = mapper.readValue(leftJson, type);
Map<String, Object> rightMap = mapper.readValue(rightJson, type);
MapDifference<String, Object> difference = Maps.difference(leftMap, rightMap);
System.out.println(difference.entriesDiffering());
// {package=([{Name=Sarah}], [{Name=Connor}])}
difference.entriesDiffering().forEach(
(key, valueDifference) -> System.out.printf(
"key: '%s'; values: left: '%s', right: '%s'",
key, valueDifference.leftValue(), valueDifference.rightValue()));
// key: 'package'; values: left: '[{Name=Sarah}]', right: '[{Name=Connor}]'
}
Related
I am using Java.
I have a Map as shown below :
List<Map<String, String>> listMap = new ArrayList<Map<String, String>>();
I am inserting Map objects with some key value pairs into the above List<Map<String, String>> listMap.
Map<String, String> map1 = new HashMap<String, String>();
map1.put("jobDescription", "Java Developer-SpringBoot");
map1.put("interviewType", "L2");
map1.put("hired", "yes");
listMap.add(map1);
Map<String, String> map2 = new HashMap<String, String>();
map2.put("jobDescription", "Java Developer-SpringBoot");
map2.put("interviewType", "L2");
map2.put("hired", "yes");
listMap.add(map2);
Map<String, String> map3 = new HashMap<String, String>();
map3.put("jobDescription", "Java Developer-SpringBoot");
map3.put("interviewType", "L1");
map3.put("hired", "no");
listMap.add(map3);
Now, I want to iterate
listMap(`List<Map<String, String>> listMap`)
and then find if there are any duplicate/same values for the key jobDescription in any of the map, then check for the value of interviewType key's value and see the number of occurrences of the value.
In the above example, the values for the key jobDescription is same in all the Map objects(i.e.Java Developer-SpringBoot). Then verify the values for the key interviewType and see the number of occurrences of each value(In the above case L2 repeated twice and L1 once). Finally I need to construct one more Map that contains my observations.
For example(This data is depicted for illustration purpose, but this should actually go into a new Map:
"jobDescription" - "Count of L2" - "Count of L1"
-------------------------------------------------------------------
"Java Developer-SpringBoot" 2 1
Can anyone help me on this?
The code that I am trying is given below:
package com.test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Sample {
public static void main(String[] args) {
List<Map<String, String>> listMap = new ArrayList<Map<String, String>>();
Map<String, String> map1 = new HashMap<String, String>();
map1.put("jobDescription", "Java Developer-SpringBoot");
map1.put("interviewType", "L2");
map1.put("hired", "yes");
listMap.add(map1);
Map<String, String> map2 = new HashMap<String, String>();
map2.put("jobDescription", "Java Developer-SpringBoot");
map2.put("interviewType", "L2");
map2.put("hired", "yes");
listMap.add(map2);
Map<String, String> map3 = new HashMap<String, String>();
map3.put("jobDescription", "Java Developer-SpringBoot");
map3.put("interviewType", "L1");
map3.put("hired", "no");
listMap.add(map3);
Map<String, Map<String, String>> requiredMap = new HashMap<String, Map<String, String>>();
for (Map<String, String> someMap : listMap) {
int count = Collections.frequency(someMap.values(), "L2");
}
}
}
It looks strange to use map to store the data, as:
All values are limited to the same type(String).
There is no limitation on the keys.
Modelling a class Job is a more proper way. Then follow #Joe comment suggestion, Group by multiple field names in java 8
Below program will output
Java Developer-SpringBoot L1:1, L2:2
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Sample {
public static void main(String[] args) {
List<Job> jobs = new ArrayList<>();
jobs.add(new Job("Java Developer-SpringBoot", "L2", "yes"));
jobs.add(new Job("Java Developer-SpringBoot", "L2", "yes"));
jobs.add(new Job("Java Developer-SpringBoot", "L1", "no"));
Map<String, Map<String, Long>> jobDescriptionToInterviewTypeToCountMapMap = jobs.stream().collect(Collectors.groupingBy(Job::getJobDescription,
Collectors.groupingBy(Job::getInterviewType, Collectors.counting())));
for (Map.Entry<String, Map<String, Long>> entry : jobDescriptionToInterviewTypeToCountMapMap.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue().entrySet().stream().map((e) ->
e.getKey() + ":" + e.getValue()).collect(Collectors.joining(", ")));
}
}
public static class Job {
public Job(String jobDescription, String interviewType, String hired) {
this.jobDescription = jobDescription;
this.interviewType = interviewType;
this.hired = hired;
}
private String jobDescription;
private String interviewType;
private String hired;
public String getJobDescription() {
return jobDescription;
}
public void setJobDescription(String jobDescription) {
this.jobDescription = jobDescription;
}
public String getInterviewType() {
return interviewType;
}
public void setInterviewType(String interviewType) {
this.interviewType = interviewType;
}
public String getHired() {
return hired;
}
public void setHired(String hired) {
this.hired = hired;
}
}
}
Stream over your list and filter maps having an entry with key: jobDescription and value: Java Developer-SpringBoot , flatmap to get all entries of all maps, filter entries having interviewType as key, map each entry to its value, collect to map using Function.identity() and mapping to frequency:
Map<String,Long> result =
listMap.stream()
.filter(m -> m.entrySet().contains(Map.entry("jobDescription","Java Developer-SpringBoot")))
.flatMap(m -> m.entrySet().stream())
.filter(e -> e.getKey().equals("interviewType"))
.map(Map.Entry::getValue)
.collect(Collectors.groupingBy(Function.identity(),Collectors.counting()));
System.out.println(result);
//output: {L1=1, L2=2}
I want to create the following object for the response but I don't want to create the class for this. Is there any way I can achieve this using map or other util classes?
"conferenceData": {
"createRequest": {
"conferenceSolutionKey": {
"type": "hangoutsMeet"
},
"requestId": "RANDOM_STRING2"
}
}
I think below is the solution you are looking for...
Map<String, Object> conferenceData = new HashMap<>();
Map<String, Object> createRequest = new HashMap<>();
Map<String, Object> keyAndRequestId= new HashMap<>();
Map<String, String> type = new HashMap<>();
type.put("type", "hangoutsMeet");
keyAndRequestId.put("conferenceSolutionKey", type);
keyAndRequestId.put("requestId", "RANDOM_STRING2");
createRequest.put("createRequest", keyAndRequestId);
conferenceData.put("conferenceData", createRequest);
Try to use :
Map<String,Object> result = new ObjectMapper().readValue(JSON_SOURCE, HashMap.class);
Or if you are using org.json, JSONObject has a method toMap(). You can easily do :
Map<String, Object> myMap = myJsonObject.toMap();
I want to map an object to json to look like this:
{"MyClass" :
[
{"key" : "value"},
{"key" : "value"}
]}
However my code is giving me:
{"MyClass" : {
"list" : {
"key" : "value",
"key" : "value"
}
And my code is like this:
public class MyClass {
private List<Map<String,String>> list;
//getters & setters......
}
And:
Map<String, String> map1 = new HashMap<String,String>();
map1.put("key", "value");
Map<String,String> map2 = new HashMap<String,String>();
map2.put("key","value");
List<Map<String,String> list = new ArrayList<Map<String,String>();
list.add(map1);
list.add(map2);
And I am using ObjectMapper to map the values. What can I do to get the layout I want?
using your code
class MyClass {
#JsonProperty("MyClass")
public List<Map<String,String>> list;
public static void main(String[] args) throws JsonProcessingException {
Map<String, String> map1 = new HashMap<String,String>();
map1.put("key", "value");
Map<String,String> map2 = new HashMap<String,String>();
map2.put("key","value");
List<Map<String,String>> list = new ArrayList<Map<String,String>>();
list.add(map1);
list.add(map2);
MyClass d = new MyClass();
d.list = list;
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(d);
System.out.println(json);
}
}
output
{"MyClass":[{"key":"value"},{"key":"value"}]}
I used #JsonProperty to change the name but you can also change the name of the var from list to whatever
Note: this is just draft implementation... don't use public class vars, and such...
I need to parse such kind of JSON:
{
"commodities": {
"39": "GOLD",
"41": "SILVER",
"42": "PLATINUM-APR16",
"85": "SUGAR (11) ",
"108": "WHEAT",
"116": "OIL-MAR16 (WTI CRUDE)",
"130": "CORN ",
"158": "COFFEE ",
"180": "ORANGE S.A.",
"282": "GOLD/JPY",
"304": "GOLD/EUR",
"332": "GOLD/TRY",
"468": "CRB INDEX",
"508": "COPPER",
...and a LOT more...
},
"currencies": {
"2": "USD/JPY",
"35": "AUD/USD",
"38": "USD/ILS",
...and a LOT more...
},
How is it possible to save this JSON to Map? So I could use it like this:
String value = mapCommodities.get(key);
String value = mapCommodities.get(39) //value equals "GOLD"
The problem is I don't know how to parse this index tag from JSON as integer value. I think it's needed to write custom Deserealizer but not really have an idea how.
create a custom deserializer
public class CustomDeserializer implements JsonDeserializer<List<Map<Integer, String>>>{
#Override
public List<Map<Integer, String>> deserialize(JsonElement element, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
List<Map<Integer, String>> randomList = new ArrayList<>();
JsonObject parentJsonObject = element.getAsJsonObject();
Map<Integer, String> childMap;
for(Map.Entry<String, JsonElement> entry : parentJsonObject.entrySet()){
childMap = new HashMap<>();
for(Map.Entry<String, JsonElement> entry1 : entry.getValue().getAsJsonObject().entrySet()){
childMap.put(Integer.parseInt(entry1.getKey()), entry1.getValue().toString());
}
randomList.add(childMap);
}
return randomList;
}
}
use it by
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(new TypeToken<ArrayList<Map<Integer, String>>>() {}.getType(), new CityListDeserializer());
Gson gson = builder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
List<Map<Integer, String>> randomList = gson.fromJson(String.valueOf(object), new TypeToken<ArrayList<Map<Integer, String>>>() {}.getType());
you can use it by
randomList.get(index).get(39);
If you want the it Map<Map<Integer, String>>, that can also be done. Will update that also. But I would't recomment that for very large data set. HashMaps will consume a considerable amount of memory
EDIT:
you can do it this way also
public class CityListDeserializer implements JsonDeserializer<Map<String, Map<Integer, String>>>{
#Override
public Map<String, Map<Integer, String>> deserialize(JsonElement element, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Map<String, Map<Integer, String>> randomList = new HashMap<>();
JsonObject parentJsonObject = element.getAsJsonObject();
Map<Integer, String> childMap;
for(Map.Entry<String, JsonElement> entry : parentJsonObject.entrySet()){
childMap = new HashMap<>();
for(Map.Entry<String, JsonElement> entry1 : entry.getValue().getAsJsonObject().entrySet()){
childMap.put(Integer.parseInt(entry1.getKey()), entry1.getValue().toString());
}
randomList.put(entry.getKey(), childMap);
}
return randomList;
}
}
use it
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(new TypeToken<Map<String, Map<Integer, String>>>() {}.getType(), new CityListDeserializer());
Gson gson = builder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
Map<String, Map<Integer, String>> randomList = gson.fromJson(String.valueOf(object), new TypeToken<Map<String, Map<Integer, String>>>() {}.getType());
access the value by
randomList.get("commodities").get(39);
this will return you GOLD
All this was for normal json parsing. Not sure but I guess just giving the typetoken like I gave will make it work for Retrofit also
This is what you can do :)
First convert the response to JSONARRAY using
JSONArray jsonArray = new JSONArray("your string");
Then you can iterate or because you know the structre of the respobnse you can simply access it like :)
JSON commodityJSON = jsonArray.getJSONObject(0);
JSON currencies = jsonArray.getJSONObject(1);
Once you get the JSON objects access it using
commodityJSON.getString("39");
commodityJSON.getString("41");
EDIT
As per your comment :) You can do something like this i believe :)
for (int i = 0; i < jsonArray.length(); ++i) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
Iterator<String> objectKeys = jsonObject.keys();
for( String s : yourKeys){
System.out.println(jsonObject.getString(s));
}
}
Will it help buddy :) Happy coding buddy :)
I'm using a Jackson library to parse JSON:
{
"employees": [
{ "firstName":"John" , "lastName":"Doe" },
{ "firstName":"Anna" , "lastName":"Smith" },
{ "firstName":"Peter" , "lastName":"Jones" }
]
}
Here is what I'm doing:
public void testJackson() throws IOException {
JsonFactory factory = new JsonFactory();
ObjectMapper mapper = new ObjectMapper(factory);
File from = new File("emp.txt"); // JSON object comes from
TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() {};
HashMap<String, Object> o = mapper.readValue(from, typeRef);
Employees employees = new Employees();
employees.employees = (List<Employer>)o.get("employees"); // retrieving list of Employer(s)
employees.showEmployer(1); // choose second to print out to console
System.out.println("Got " + o); // just result of file reading
}
public static class Employees {
public List<Employer> employees;
public void showEmployer(int i) {
System.out.println(employees.get(i));
}
}
public static class Employer {
public String firstName;
public String lastName;
}
The output I'm getting:
{firstName=Anna, lastName=Smith}
Got {employees=[{firstName=John,
lastName=Doe}, {firstName=Anna, lastName=Smith}, {firstName=Peter,
lastName=Jones}]}
But I'm not expecting the elements in my List to be HashMap instances, but Employer objects. This is what Jackson library is supposed to be, isn't it? Could you guys correct me where I am wrong?
I haven't used Jackson, but it seems you're getting what you asked for - a HashMap of String, Object pairs. Perhaps you need to be more explicit in the 'value' portion of the map? Since the value is an array of Employee objects, you might try:
TypeReference<HashMap<String, List<Employee>>> typeRef = new TypeReference<HashMap<String, List<Employee>>>() {};
HashMap<String, List<Employee>> o = mapper.readValue(from, typeRef);