Group and Aggregate List of Map<String, Object> - java

I have a List<Map<String, Object>> input like below:
[{
CURRENCY = USD,
STATUS = NEW,
PUBLISH_REGION = DEL,
SOURCE = ALADDIN,
RECON_STATUS = null,
JOB_ID_COUNT = 783
}, {
CURRENCY = USD,
STATUS = IN_PROGRESS,
PUBLISH_REGION = DEL,
SOURCE = ALADDIN,
RECON_STATUS = null,
JOB_ID_COUNT = 462
}, {
CURRENCY = USD,
STATUS = NEW,
PUBLISH_REGION = DEL,
SOURCE = GROUP,
RECON_STATUS = null,
JOB_ID_COUNT = 4
}]
I am trying to create another List<Map<String, Object>> by grouping on CURRENCY, PUBLISH_REGION, SOURCE and RECON_STATUS columns. And add all unique STATUS values as pivot to the output map and use JOB_ID_COUNT to summarize/aggregate the count.
List<String> groups = new ArrayList<>(asList("SOURCE", "RECON_STATUS", "PUBLISH_REGION", "CURRENCY"));
List<Map<String, Object>> = input.stream()
.collect(groupingBy(row -> row.get(groups.get(0)), mapping(map -> map.get(groups.get(0)), toList())));
I am expecting below response:
Output:
[{
CURRENCY = USD,
PUBLISH_REGION = DEL,
SOURCE = ALADDIN,
RECON_STATUS = null,
NEW = 783,
IN_PROGRESS = 462
}, {
CURRENCY = USD,
PUBLISH_REGION = DEL,
SOURCE = GROUP,
RECON_STATUS = null,
NEW = 4,
IN_PROGRESS = 0
}]
I am getting compile time error when trying to group by multiple map fields. Single field groupingBy is working fine. Any help is greatly appriciated.

Without Using Custom Class
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MultipleFieldSorting2 {
private static Map<String, Object> map, map1, map2;
private static List<Map<String, Object>> lst = new ArrayList<>();
static {
map = new HashMap<>();
map.put("CURRENCY", "USD");
map.put("STATUS", "NEW");
map.put("PUBLISH_REGION", "DEL");
map.put("SOURCE", "ALADDIN");
map.put("RECON_STATUS", null);
map.put("JOB_ID_COUNT", "783");
map1 = new HashMap<>();
map1.put("CURRENCY", "USD");
map1.put("STATUS", "IN_PROGRESS");
map1.put("PUBLISH_REGION", "DEL");
map1.put("SOURCE", "ALADDIN");
map1.put("RECON_STATUS", null);
map1.put("JOB_ID_COUNT", "462");
map2 = new HashMap<>();
map2.put("CURRENCY", "USD");
map2.put("STATUS", "NEW");
map2.put("PUBLISH_REGION", "DEL");
map2.put("SOURCE", "GROUP");
map2.put("RECON_STATUS", null);
map2.put("JOB_ID_COUNT", "4");
lst.add(map);
lst.add(map1);
lst.add(map2);
}
public static Map<String, Object> mapper(Map<String, Object> e){
String key = e.get("CURRENCY") + "-" + e.get("PUBLISH_REGION") + "-" + e.get("SOURCE") + "-" + e.get("RECON_STATUS");
Map<String, Object> groupedValue = res.get(key);
if(groupedValue!=null){
groupedValue.put((String) e.get("STATUS"), groupedValue.get("STATUS")!=null ? groupedValue.get("STATUS")+","+e.get("JOB_ID_COUNT") : e.get("JOB_ID_COUNT"));
if(groupedValue.get("NEW")==null){
groupedValue.put("NEW", 0);
}
if(groupedValue.get("IN_PROGRESS")==null){
groupedValue.put("IN_PROGRESS", 0);
}
}else{
groupedValue = new HashMap<>();
res.put(key, groupedValue);
groupedValue.put("CURRENCY", e.get("CURRENCY"));
groupedValue.put("PUBLISH_REGION", e.get("PUBLISH_REGION"));
groupedValue.put("SOURCE", e.get("SOURCE"));
groupedValue.put("RECON_STATUS", e.get("RECON_STATUS"));
groupedValue.put((String) e.get("STATUS"), e.get("JOB_ID_COUNT"));
}
return groupedValue;
}
static Map<String, Map<String, Object>> res = new HashMap<>();
public static void main(String[] args) {
List<Map<String, Object>> finalResult = new ArrayList<>();
lst.stream()
.map(MultipleFieldSorting2::mapper)
.forEach(result -> {
if(!finalResult.contains(result))
finalResult.add(result);
});
System.out.println(finalResult);
}
}

Tried this solution and it is working
Stream the source List
Map each value of map in the list to Class MapWrapper(a pojo where each key is a field)
GroupBy using the groupByKey defined in MapWrapper(uses CURRENCY, PUBLISH_REGION, SOURCE and RECON_STATUS columns)
3.a The result is a Map<String, List<MapWrapper>>
4.Stream through the entry set
map - and get the value alone from (Map<String, List<MapWrapper>>)
Map - convert from List<MapWrapper> to Map<String, Object> using MapWrapper::map
Collect to a list
In Short the solution is
List<Map<String, Object>> value = lst.stream()
.map(map -> new MapWrapper(map))
.collect(groupingBy(MapWrapper::groupByKey))
.entrySet()
.stream()
.map(e -> e.getValue())
.map(MapWrapper::map).collect(toList());
Working Code
public class MultipleFieldSorting {
private static Map<String, Object> map, map1, map2;
private static List<Map<String, Object>> lst = new ArrayList<>();
static {
map = new HashMap<>();
map.put("CURRENCY", "USD");
map.put("STATUS", "NEW");
map.put("PUBLISH_REGION", "DEL");
map.put("SOURCE", "ALADDIN");
map.put("RECON_STATUS", null);
map.put("JOB_ID_COUNT", "783");
map1 = new HashMap<>();
map1.put("CURRENCY", "USD");
map1.put("STATUS", "IN_PROGRESS");
map1.put("PUBLISH_REGION", "DEL");
map1.put("SOURCE", "ALADDIN");
map1.put("RECON_STATUS", null);
map1.put("JOB_ID_COUNT", "462");
map2 = new HashMap<>();
map2.put("CURRENCY", "USD");
map2.put("STATUS", "NEW");
map2.put("PUBLISH_REGION", "DEL");
map2.put("SOURCE", "GROUP");
map2.put("RECON_STATUS", null);
map2.put("JOB_ID_COUNT", "4");
lst.add(map);
lst.add(map1);
lst.add(map2);
}
public static void main(String[] args) {
List<Map<String, Object>> value = lst.stream()
.map(map -> new MapWrapper(map))
.collect(groupingBy(MapWrapper::groupByKey))
.entrySet()
.stream()
.map(e -> e.getValue())
.map(MapWrapper::map).collect(toList());
System.out.println(value);
}
}
class MapWrapper {
private String currency;
private String status;
private String publish;
private String source;
private String recon_status;
private String job_id;
public MapWrapper(Map<String, Object> map) {
this.currency = (String) map.get("CURRENCY");
this.status = (String) map.get("STATUS");
this.publish = (String) map.get("PUBLISH_REGION");
this.source = (String) map.get("SOURCE");
this.recon_status = (String) map.get("RECON_STATUS");
this.job_id = (String) map.get("JOB_ID_COUNT");
}
String groupByKey() {
return new StringBuilder().append(this.getCurrency()).append("-").append(this.publish).append("-")
.append(this.source).append("-").append(this.recon_status).toString();
}
public static Map<String, Object> map(List<MapWrapper> lst){
Map<String, Object> res = new HashMap<>();
res.put("CURRENCY",lst.get(0).getCurrency());
res.put("PUBLISH_REGION",lst.get(0).getPublish());
res.put("SOURCE",lst.get(0).getSource());
res.put("RECON_STATUS",lst.get(0).getRecon_status());
for(MapWrapper m : lst){
res.put(m.getStatus(), m.getJob_id());
}
if(res.get("NEW")==null){
res.put("NEW", 0);
}
if(res.get("IN_PROGRESS")==null){
res.put("IN_PROGRESS", 0);
}
return res;
}
String getCurrency() {
return currency;
}
void setCurrency(String currency) {
this.currency = currency;
}
String getStatus() {
return status;
}
void setStatus(String status) {
this.status = status;
}
String getPublish() {
return publish;
}
void setPublish(String publish) {
this.publish = publish;
}
String getSource() {
return source;
}
void setSource(String source) {
this.source = source;
}
String getJob_id() {
return job_id;
}
void setJob_id(String job_id) {
this.job_id = job_id;
}
String getRecon_status() {
return recon_status;
}
void setRecon_status(String recon_status) {
this.recon_status = recon_status;
}
}

Related

Updating HashMap values by reference replaces all values with the last updated value

Here is my code which passes a map to update the values. The products for all the value objects in the map is exactly the same which should not happen. The data is verified and I have different products for every case.
public void mapCustomerData(Map<String, ExportDto> casesMap) {
List<String> cins = new ArrayList<>(casesMap.keySet());
populateProducts(casesMap, cins);
}
#Transactional(readOnly = true)
public void populateProducts(Map<String, ExportDto> casesMap, List<String> cins) {
try {
List<ProductDto> products = service.retrieveProductsByCins(cins);
// TODO: fix it
casesMap.replaceAll((key, value) -> {
value.setProducts(products.stream()
.filter(p -> equalsIgnoreCase(p.getCin(), key))
.collect(toList()));
return value;
});
} catch (CustomerGenericException e) {
log.error("some error msg", e);
}
}
Attempt #2:
#Transactional(readOnly = true)
public void populateProducts(Map<String, ExportDto> casesMap, List<String> cins) {
try {
List<ProductDto> customerProducts = service.ProductDto(cins);
casesMap.keySet().forEach(key -> casesMap.get(key).setProducts(products.stream()
.filter(p -> equalsIgnoreCase(p.getCin(), key))
.collect(toList())));
} catch (CustomerGenericException e) {
log.error("some error msg", e);
}
}
Can anyone help with the same?
The following code works as expected:
public static void main(String[] args) {
String cin1 = "cin1";
String cin2 = "cin2";
String cin3 = "cin3";
String cin4 = "cin4";
String cin5 = "cin5";
List<ProductDto> customerProducts = new ArrayList<>();
customerProducts.add(new ProductDto(cin1));
customerProducts.add(new ProductDto(cin2));
customerProducts.add(new ProductDto(cin3));
customerProducts.add(new ProductDto(cin4));
customerProducts.add(new ProductDto(cin5));
Map<String, ExportDto> casesMap = new HashMap<>();
casesMap.put(cin1, new ExportDto());
casesMap.put(cin2, new ExportDto());
casesMap.put(cin3, new ExportDto());
casesMap.put(cin4, new ExportDto());
casesMap.put(cin5, new ExportDto());
casesMap.keySet().forEach(key -> casesMap.get(key).setProducts(customerProducts.stream()
.filter(p -> p.getCin().equalsIgnoreCase(key))
.collect(toList())));
System.out.println(casesMap);
}
Which means that the following should also work:
#Transactional(readOnly = true)
public void populateProducts(Map<String, ExportDto> casesMap, List<String> cins) {
try {
List<ProductDto> customerProducts = service.ProductDto(cins);
casesMap.keySet().forEach(key -> casesMap.get(key).setProducts(customerProducts.stream()
.filter(p -> p.getCin().equalsIgnoreCase(key))
.collect(toList())));
} catch (CustomerGenericException e) {
log.error("some error msg", e);
}
}
The only reason that could lead to the behaviour that you describe is if casesMap includes only references for the same ExportDto instance, as the following code proves:
public static void main(String[] args) {
String cin1 = "cin1";
String cin2 = "cin2";
String cin3 = "cin3";
String cin4 = "cin4";
String cin5 = "cin5";
List<ProductDto> customerProducts = new ArrayList<>();
customerProducts.add(new ProductDto(cin1));
customerProducts.add(new ProductDto(cin2));
customerProducts.add(new ProductDto(cin3));
customerProducts.add(new ProductDto(cin4));
customerProducts.add(new ProductDto(cin5));
Map<String, ExportDto> casesMap = new HashMap<>();
ExportDto exportDto = new ExportDto();
casesMap.put(cin1, exportDto);
casesMap.put(cin2, exportDto);
casesMap.put(cin3, exportDto);
casesMap.put(cin4, exportDto);
casesMap.put(cin5, exportDto);
casesMap.keySet().forEach(key -> casesMap.get(key).setProducts(customerProducts.stream()
.filter(p -> p.getCin().equalsIgnoreCase(key))
.collect(toList())));
System.out.println(casesMap);
}
If this is the case, then you need to add a new constructor in ExportDto that accepts an ExportDto object, actually copying it:
public class ExportDto {
private List<ProductDto> products = new ArrayList<>();
public ExportDto(ExportDto value) {
this.products = new ArrayList<>(value.getProducts());
}
(...)
}
And then you can use casesMap.forEach((key, value) -> casesMap.put(key, new ExportDto(value))); to create the new ExportDto. This will fix it as the following shows:
public static void main(String[] args) {
String cin1 = "cin1";
String cin2 = "cin2";
String cin3 = "cin3";
String cin4 = "cin4";
String cin5 = "cin5";
List<ProductDto> customerProducts = new ArrayList<>();
customerProducts.add(new ProductDto(cin1));
customerProducts.add(new ProductDto(cin2));
customerProducts.add(new ProductDto(cin3));
customerProducts.add(new ProductDto(cin4));
customerProducts.add(new ProductDto(cin5));
Map<String, ExportDto> casesMap = new HashMap<>();
ExportDto exportDto = new ExportDto();
casesMap.put(cin1, exportDto);
casesMap.put(cin2, exportDto);
casesMap.put(cin3, exportDto);
casesMap.put(cin4, exportDto);
casesMap.put(cin5, exportDto);
casesMap.forEach((key, value) -> casesMap.put(key, new ExportDto(value)));
casesMap.keySet().forEach(key -> casesMap.get(key).setProducts(customerProducts.stream()
.filter(p -> p.getCin().equalsIgnoreCase(key))
.collect(toList())));
System.out.println(casesMap);
}

parsing HashMap into xml with Simple XML - JAVA

I need to put the values inside a pat as the values of my XML file for Ex:
Map<String, String> props = new HashMap<>();
props.put("role", "Admin");
props.put("externalId", "2ew1Q");
props.put("Property", "internal");
props.put("Execution", "internal");
My expected output should be:
<role>Admin</role>
<externalId>2ew1Q</externalId>
<Property>internal</Property>
<Execution>internal</Execution>
But instead of it, I'm getting
<entry string="role">Admin</entry>
<entry string="Execution">internal</entry>
<entry string="externalId">2ew1Q</entry>
<entry string="Property">internal</entry>
I have to do it with Simple XML, and this is my code:
#Root
public class Data {
#ElementMap(entry = "property", key = "key", attribute = true, inline = true)
private Map<String, String> customProps;
public Map<String, String> getData() {
return customProps;
}
public void setData(Map<String, String> data) {
this.customProps = data;
}
}
public static void main(String[] args) throws Exception {
Map<String, String> props = new HashMap<>();
props.put("role", "Admin");
props.put("externalId", "2ew1Q");
props.put("Property", "internal");
props.put("Execution", "internal");
Data customProps = new Data();
customProps.setData(props);
Serializer serializer = new Persister();
File result = new File("example.xml");
serializer.write(customProps, result);
}
Try:
#ElementMap(entry = "property", key = "key", attribute = false, inline = true)

initiallize the java bean using multiple values for ElasticSearch indexing

Am trying to create a java class where i want to create indexing in ElasticSearch. Actual data are available from REST API, but for testing my indexing code i have written a logic.
But now, i want to test my indexing code with few dummy data. For that i have created a bean class and using setter/getter i want to replicate the actual scenario for indexing documents in elasticsearch.
Please find my java code below :
public static void main(String args[]) throws IOException
{
System.out.println("Indexing via Java Code ....");
Product prod1=new Product("1001", 123172l, "Product", "VG3000");
Product prod2=new Product("1002", 123172l, "Series", "Valves, VG3000");
Product prod3=new Product("1003", 123172l, "Series", "Activa RoofTop, VG3000");
Product prod4=new Product("1004", 123172l, "Product", "Activa RoofTop VG3000, 3000");
Product prod=new Product();
Map<String, Object> jsonMap ;
for(int i=1;i<4;i++)
{
jsonMap = new HashMap<String, Object>();
jsonMap.put("id", prod.getId());
jsonMap.put("catalog_id", prod.getCatalog_id());
jsonMap.put("catalog_type", prod.getCatalog_type());
jsonMap.put("values", prod.getValues());
IndexRequest request = new IndexRequest(INDEX_NAME, "doc", prod.getId() )
.source(jsonMap);
try {
IndexResponse response = SearchEngineClient.getInstance3().index(request); // increased timeout
} catch(ElasticsearchException e) {
if (e.status() == RestStatus.CONFLICT) {
}
e.printStackTrace();
}
}
System.out.println("Indexing done....");
}
Please find my bean class :
public class Product {
public Product(String id, long catalog_id, String Catalog_type, String values)
{
this.id=id;
this.catalog_id=catalog_id;
this.catalog_type=catalog_type;
this.values=values;
}
public Product()
{
}
private String id;
private long catalog_id;
private String catalog_type;
private String values;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Long getCatalog_id() {
return catalog_id;
}
public void setCatalog_id(Long catalog_id) {
this.catalog_id = catalog_id;
}
public String getCatalog_type() {
return catalog_type;
}
public void setCatalog_type(String catalog_type) {
this.catalog_type = catalog_type;
}
public String getValues() {
return values;
}
public void setValues(String values) {
this.values = values;
}
}
But, while indexing am getting the value from bean class which all the data coming as null.
**Update 1 :
I have modified the code in the below way :
public static void main(String args[]) throws IOException
{
System.out.println("Indexing via Java Code ....");
Product prod1=new Product("1001", 123172l, "Product", "VG3000");
Product prod2=new Product("1002", 123172l, "Series", "Valves, VG3000");
Product prod3=new Product("1003", 3536633, "Series", "Activa RoofTop, VG3000 abcd");
Product prod4=new Product("1004", 123172l, "Product", "Activa RoofTop VG3000, 3000");
Product prod=new Product();
IndexRequest request;
Map<String, Object> jsonMap ;
jsonMap = new HashMap<String, Object>();
jsonMap.put("id", prod1.getId());
jsonMap.put("catalog_id", prod1.getCatalog_id());
jsonMap.put("catalog_type", prod1.getCatalog_type());
jsonMap.put("values", prod1.getValues());
request = new IndexRequest(INDEX_NAME, "doc", prod1.getId() )
.source(jsonMap);
IndexResponse response1 = SearchEngineClient.getInstance3().index(request);
jsonMap = new HashMap<String, Object>();
jsonMap.put("id", prod2.getId());
jsonMap.put("catalog_id", prod2.getCatalog_id());
jsonMap.put("catalog_type", prod2.getCatalog_type());
jsonMap.put("values", prod2.getValues());
request = new IndexRequest(INDEX_NAME, "doc", prod2.getId() )
.source(jsonMap);
IndexResponse response2 = SearchEngineClient.getInstance3().index(request);
jsonMap = new HashMap<String, Object>();
jsonMap.put("id", prod3.getId());
jsonMap.put("catalog_id", prod3.getCatalog_id());
jsonMap.put("catalog_type", prod3.getCatalog_type());
jsonMap.put("values", prod3.getValues());
request = new IndexRequest(INDEX_NAME, "doc", prod3.getId() )
.source(jsonMap);
IndexResponse response3 = SearchEngineClient.getInstance3().index(request);
jsonMap = new HashMap<String, Object>();
jsonMap.put("id", prod4.getId());
jsonMap.put("catalog_id", prod4.getCatalog_id());
jsonMap.put("catalog_type", prod4.getCatalog_type());
jsonMap.put("values", prod4.getValues());
request = new IndexRequest(INDEX_NAME, "doc", prod4.getId() )
.source(jsonMap);
IndexResponse response4 = SearchEngineClient.getInstance3().index(request);
System.out.println("Indexing done....");
}
Is there any other way to simplify the same.?

Restructuring JSON file in JAVA

I am having the following sample from a JSON file:
[
{
"0":
{
"File":"file1.java",
"Class":"com.ETransitionActionType",
"Method":"values",
"Annotation":"Not Found"
}
},
{
"1":
{
"File":"file2.java",
"Class":"com.ETransitionParams",
"Method":"values",
"Annotation":"Not Found"
}
},
{
"2":
{
"File":"file3.java",
"Class":"com.phloc.commons.id.IHasID",
"Method":"getID",
"Annotation":"Not Found"
}
},
{
"4":
{
"File":"file3.java",
"Class":"com.ExecuteTransitionActionHandler",
"Method":"createBadRequestResponse",
"Annotation":"Not Found"
}
},
{
"5":
{
"File":"file3.java",
"Class":"com.ExecuteTransitionActionHandler",
"Method":"extractParametersFromAction",
"Annotation":"Not Found"
}
}]
How can I restructure this file using java so that it looks like:
[{
"file1.java": {
"com.ETransitionActionType": {
"values": {
"Annotation": "Not Found"
}
}
}
},
{
"file2.java": {
"com.ETransitionParams": {
"values": {
"Annotation": "Not Found"
}
}
}
},
{
"file3.java": {
"com.phloc.commons.id.IHasID": {
"getID": {
"Annotation": "Not Found"
}
},
"com.ExecuteTransitionActionHandler": {
"getID": {
"Annotation": "Not Found"
},
"extractParametersFromAction": {
"Annotation": "Not Found"
}
}
}
}
]
i.e. Going through the JSON file, searching it, and wherever the "File" attribute has the same value("file3.java" for example), we list all the relevant classes and methods inside and the same applies for the "Class" attribute, if it has the same name, we list all the methods inside it(So it's like comparing and sorting the values for the "File" and "Class" attributes).
I started with JSON simple library and wrote like the code below, but don't know how to go further!
Object object = (JSONArray)parser.parse(new FileReader("rawOutput.json"));
JSONArray jsonArray = (JSONArray) object;
for(int i = 0; i < jsonArray.size(); i++) {
System.out.println(jsonArray.get(i));
JSONObject jsonObject = (JSONObject)jsonArray.get(i);
String c = jsonObject.get("" + i + "").toString();
}
Any ideas? Your help is really appreciated!!!
I wrote a code to do what do you need but first you have to add this library to your project if you don't have already org.json.zip library, because I didn't have a library for parsing Json texts so I used this library for formatting the Json data, and I'm sorry if you don't understand the code completely because your request isn't so easy as yourself know and I created three functions to get the result and although I wrote some comments to understand easily, this is the code:-
Edit
...
import org.json.*;
...
...
public static void main(String[] args) throws JSONException {
System.out.println(getFormattedJson("json text"));
}
private static String getFormattedJson(String text) throws JSONException{
JSONArray result = new JSONArray();
JSONArray jsonArray = null;
//get the json array
jsonArray = new JSONArray(text);
//loop through items in the array and insert them formatted to the result
for (int i = 0; i < jsonArray.length(); i++) {
//get object inside the number
JSONObject object = getJsonChild(jsonArray.getJSONObject(i));
//get these attributes
String file = object.getString("File");
String clas = object.getString("Class");
String meth = object.getString("Method");
String anno = object.getString("Annotation");
//create a custom type of the object's attributes
Map<String, String> map = new HashMap<>();
map.put("Annotation", anno);
Map<String, Object> map1 = new HashMap<>();
map1.put(meth, map);
Map<String, Object> map2 = new HashMap<>();
map2.put(clas, map1);
Map<String, Object> map3 = new HashMap<>();
map3.put(file, map2);
//loop through repeating values to also add them to one value as you expected
for (int j = jsonArray.length() - 1; j > i; j--) {
JSONObject obj = getJsonChild(jsonArray.getJSONObject(j));
String file1 = obj.getString("File");
String clas1 = obj.getString("Class");
String meth1 = obj.getString("Method");
String anno1 = obj.getString("Annotation");
if (file1.equals(file)) {
if (map2.containsKey(clas1)) {
if (childrenContains(map2, meth1)) {
//if the difference was annotation value
map.put("Annotation", anno1);
} else {
//if the difference was method names
Map<String, String> map_ = new HashMap<>();
map_.put("Annotation", anno1);
((Map<String, Object>) map2.get(clas1)).put(meth1, map_);
}
} else {
//if the difference was class names
Map<String, String> map_ = new HashMap<>();
map_.put("Annotation", anno1);
Map<String, Object> map1_ = new HashMap<>();
map1_.put(meth1, map_);
map2.put(clas1, map1_);
}
//remove the (value added) object
jsonArray.remove(j);
}
}
//add the map to the result
result.put(map3);
}
return result.toString(4);
}
private static boolean childrenContains(Map<String, Object> map1, String meth1) {
for (String childKey : map1.keySet()) {
Map<String, Object> child = (Map<String, Object>) map1.get(childKey);
if (child.containsKey(meth1))
return true;
}
return false;
}
private static JSONObject getJsonChild(JSONObject object) throws JSONException {
Iterator<String> keys = object.keys();
String key = "";
while (keys.hasNext()) {
key = (String) keys.next();
}
return object.getJSONObject(key);
}
And the result for your sample using my code is:-
[
{"file1.java": {"com.ETransitionActionType": {"values": {"Annotation": "Not Found"}}}},
{"file2.java": {"com.ETransitionParams": {"values": {"Annotation": "Not Found"}}}},
{"file3.java": {
"com.ExecuteTransitionActionHandler": {
"createBadRequestResponse": {"Annotation": "Not Found"},
"extractParametersFromAction": {"Annotation": "Not Found"}
},
"com.phloc.commons.id.IHasID": {"getID": {"Annotation": "Not Found"}}
}}
]
And if you want to get the json data from a file so use the following function to create the JSONArray easily:-
private static JSONArray readFromFile(String filePath){
try {
BufferedReader br = new BufferedReader(new FileReader(filePath));
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append(System.lineSeparator());
line = br.readLine();
}
return new JSONArray(sb.toString());
} catch (Exception e) {
System.out.println(e.getMessage());
return null;
}
}
And use it instead the text json data:-
...
//get the json array
jsonArray = readFromFile("FilePath");
...
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public class Foo {
public static void main(String... args) throws IOException {
String json = formatJson(new FileReader("rawOutput.json"));
System.out.println(json);
}
public static String formatJson(Reader reader) throws IOException {
// group array items by fileName
final Function<List<Map<String, Object>>, Map<String, List<Object>>> groupByFileName =
data -> data.stream().collect(Collectors.groupingBy(map -> (String)map.get("File"), TreeMap::new,
Collectors.mapping(Function.identity(), Collectors.toList())));
// convert source item structure into required
final Function<Map.Entry<String, List<Object>>, Map<String, Object>> convert = entry -> {
Map<String, Map<String, Map<String, String>>> tmp = new LinkedHashMap<>();
entry.getValue().stream()
.map(value -> (Map<String, String>)value)
.forEach(map -> {
Map<String, Map<String, String>> classes = tmp.computeIfAbsent(map.get("Class"), cls -> new TreeMap<>());
Map<String, String> methods = classes.computeIfAbsent(map.get("Method"), method -> new TreeMap<>());
map.entrySet().stream()
.filter(e -> !"Class".equals(e.getKey()) && !"Method".equals(e.getKey()) && !"File".equals(e.getKey()))
.forEach(e -> methods.put(e.getKey(), e.getValue()));
});
return Collections.singletonMap(entry.getKey(), tmp);
};
ObjectMapper mapper = new ObjectMapper();
// read json as array of Maps
List<Map<String, Object>> data = Arrays.stream(mapper.readValue(reader, Map[].class))
.map(map -> map.values().iterator().next())
.map(item -> (Map<String, Object>)item)
.collect(Collectors.toList());
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(groupByFileName.apply(data).entrySet().stream()
.map(convert).collect(Collectors.toList()));
}
}
You could create a map of maps to represent your grouping by "File" and "Class" for your list of (inner) JSON objects. It might look similar to
final Function<JSONObject, String> fileFunction = (JSONObject jsonObject) -> jsonObject.getString("File");
final Function<JSONObject, String> classFunction = (JSONObject jsonObject) -> jsonObject.getString("Class");
final Map<String, Map<String, List<JSONObject>>> groupedJsonObjects = jsonObjects.stream()
.collect(Collectors.groupingBy(fileFunction, Collectors.groupingBy(classFunction)));

Can't retrieve Double from HashMap<Integer, Double>

Somehow I can't retrieve a Double from a HashMap I've made using Gson.
Map<Integer, Double> ratingMap = (Map<Integer, Double>) new GsonBuilder()
.create().fromJson(json, Map.class);
Integer ifilmId = filmId;
Double rating = ratingMap.get(ifilmId);
In this code I've veried that the ratingMap contains {2=5.0}, but when I do ratingMap.get(ifilmId) (where I've verified that ifilmId is in fact 2), the variable rating is null. Am I missing something here?
I create the HashMap in the following way:
if (json.equals("")) {
// noting ever saved
ratingMap = new HashMap<Integer, Integer>();
ratingMap.put(filmId, rating);
} else {
ratingMap = (Map<Integer, Integer>) new GsonBuilder().create()
.fromJson(json, Map.class);
ratingMap.put(Integer.valueOf(filmId), rating);
}
I let Gson format the Integer to a Double, and that seems to work fine but I can't retrieve it.
The total code, including saving to Androids SharedPreferences
public void saveRating(int rating, int filmId) {
SharedPreferences sharedPref = context.getSharedPreferences(
LOCAL_MEM_KEY, 0);
String json = sharedPref.getString(LOCAL_MAP_RATING_KEY, "");
Map<Integer, Integer> ratingMap;
if (json.equals("")) {
// noting ever saved
ratingMap = new HashMap<Integer, Integer>();
ratingMap.put(filmId, rating);
} else {
ratingMap = (Map<Integer, Integer>) new GsonBuilder().create()
.fromJson(json, Map.class);
ratingMap.put(Integer.valueOf(filmId), rating);
}
json = new GsonBuilder().create().toJson(ratingMap, Map.class);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString(LOCAL_MAP_RATING_KEY, json);
editor.commit();
}
/*
* returns null if no rating found
*/
public Map<Integer, Integer> getRatingFor(int filmId) {
SharedPreferences sharedPref = context.getSharedPreferences(
LOCAL_MEM_KEY, 0);
String json = sharedPref.getString(LOCAL_MAP_RATING_KEY, "");
if (json.equals("")) {
return null;
}
Map<Integer, Integer> ratingMap = (Map<Integer, Integer>) new GsonBuilder()
.create().fromJson(json, Map.class);
Log.d("map", ratingMap.toString());
Integer ifilmId = filmId;
Integer rating = ratingMap.get(ifilmId);
if(rating == null) { //because of this we have to prevent a 0 rating
return null;
} else {
Map<Integer, Integer> returnMap = new HashMap<Integer, Integer>();
returnMap.put(filmId, rating.intValue());
return returnMap;
}
}
Make sure your not passing a null variable when saving
saveRating(int rating, int filmId){
Log.d(TAG, String.valueOf(rating));
}
if (json.equals("")) {
// noting ever saved
ratingMap = new HashMap<Integer, Double>(); <--- Double not Integer
ratingMap.put(filmId, 5.0);
} else {
ratingMap = (Map<Integer, Double>) new GsonBuilder().create()
.fromJson(json, Map.class); <--- double not Integer
ratingMap.put(Integer.valueOf(filmId), 5.0);
}
Make sure when using Doubles to
use 5.0
not 5
public void saveRating(Double rating, int filmId) {
SharedPreferences sharedPref = context.getSharedPreferences(LOCAL_MEM_KEY, 0);
String json = sharedPref.getString(LOCAL_MAP_RATING_KEY, "");
Map<Integer, Double> ratingMap;
if (json.equals("")) {
// noting ever saved
ratingMap = new HashMap<Integer, Double>();
} else {
ratingMap = (Map<Integer, Double>) new GsonBuilder().create().fromJson(json, Map.class);
}
ratingMap.put(filmId, rating);
ratingMap.put(3, 5.0d); // JUST FOR TEST
json = new GsonBuilder().create().toJson(ratingMap, Map.class);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString(LOCAL_MAP_RATING_KEY, json);
editor.commit();
}
/*
* returns null if no rating found
*/
public Map<Integer, Double> getRatingFor(int filmId) {
SharedPreferences sharedPref = context.getSharedPreferences(LOCAL_MEM_KEY, 0);
String json = sharedPref.getString(LOCAL_MAP_RATING_KEY, "");
if (json.equals("")) {
return null;
}
Map<Integer, Double> ratingMap = (Map<Integer, Double>) new GsonBuilder().create().fromJson(json, Map.class);
Log.d("map", ratingMap.toString());
Log.d("map", ratingMap.get(3) + ""); // JUST FOR TEST
Integer ifilmId = filmId;
Double rating = ratingMap.get(ifilmId);
if (rating == null) { //because of this we have to prevent a 0 rating
return null;
} else {
Map<Integer, Double> returnMap = new HashMap<Integer, Double>();
returnMap.put(filmId, rating);
return returnMap;
}
}

Categories

Resources