how to convert complex hashmap to arrayList - java

I have converted this JSON to Hashmap
http://www.mocky.io/v2/5d0dc72d3400008c00ca4a62
I have nested Hashmap and I wanted to convert it to ArrayList
Map<String, Bank> stringBankMap = getValues();
I want to get all the data from stringBankMap and add to the list. I want also the key to the hashmap to also will be imported on the list as a guide.
Here is Bank class
public class Bank {
private String guid;
private String title;
private long date;
private String logo;
private HashMap<String, HashMap<String, BankList>> list;
}
Here is BankList class
public class BankList {
private double buy;
private double sell;
private String currency;
}
What I tried
for(Map.Entry<String, Bank> entry1 : stringBankMap.entrySet()) {
Bank newBank = new Bank(entry1.getKey());
Bank bank = entry1.getValue();
newBank.setDate(bank.getDate());
newBank.setLogo(bank.getLogo());
newBank.setTitle(bank.getTitle());
List<BankList> bankListList = new ArrayList<>();
for(Map.Entry<String, HashMap<String, BankList>> entry2 : bank.getList().entrySet()) {
HashMap<String, BankList> map = entry2.getValue();
for (Map.Entry<String, BankList> entry3 : map.entrySet()) {
BankList newBankList = new BankList(entry3.getKey());
BankList bankList = entry3.getValue();
newBankList.setBuy(bankList.getBuy());
newBankList.setSell(bankList.getSell());
bankListList.add(newBankList);
}
}
bankArrayList.add(newBank);
}
But I don't understand why I am getting an exception
Please suggest me other algorithms if you can
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to core.model.Bank

you can do it this way : make a class node with data members String key and Bank value like
`class Node{
String key;
Bank value;
Node(String k,Bank val){
key=k;
value=val;
}
}`
then make an ArrayList of class Node ,then add elements to the list as [list name].add(new Node([pass key and value here]) by traversing through the map like here
and then you can traverse the list in the desired order and get your elements by [arraylist name].get(index).key or [arraylist name].get(index).value

Related

groupping list of objects based on properties in java

I have POJO List<TravelRequestDTO> and I want to group and create filtered List<TravelRequestDTO> if leavingFrom,goingTo,onwarDate,returnDate are same add passenger to same object
Example :
Passanger, onWard, return, leavingFrom, goingTo
A, 1-2-20, 3-2-20, BLR, PUNE
B, 1-2-20 , 3-2-20, BLR, PUNE
final List<TravelRequestDTO> should contain :
Passanger, onWard, return, leavingFrom, goingTo
A,B 1-2-20 3-2-20 BLR PUNE
public class TravelRequestDTO {
private List<Pax> passangers;
private String leavingFrom;
private String goingTo;
private String onwarDate;
private String onwardTime;
private String returnDate;
private String returnTime;
private SegmentTypeEnum segmentType;
private TravelModeEnum travelMode;
private String purposeOfVisit;
}
public class Pax{
private String name;
private String age;
private String mobile;
}
If you need older java version, than you can do like this:
Map<Object, List<TravelRequestDTO>> hashMap = new HashMap<Object, List<TravelRequestDTO>>();
for (TravelRequestDTO value: initList) {
List<Object> key = Arrays.asList(value.getOnWard(),value.getReturn(),value.getLeavingFrom(),value.getGoingTo());
if (!hashMap.containsKey(key)) {
List<TravelRequestDTO> list = new ArrayList<TravelRequestDTO>();
list.add(value);
hashMap.put(key, list);
} else {
hashMap.get(key).add(value);
}
}
Check this question for other solution.
It is only half way to what you want. After that you have to extract final result from this map. Or you can do it in one step:
Map<Object, TravelRequestDTO> hashMap = new HashMap<Object, TravelRequestDTO>();
for (TravelRequestDTO value: initList) {
List<Object> key = Arrays.asList(value.getOnWard(),value.getReturn(),value.getLeavingFrom(),value.getGoingTo());
if (!hashMap.containsKey(key)) {
TravelRequestDTO item = value; // pass first value or copy it to new
hashMap.put(key, item);
} else {
hashMap.get(key).getPassangers().addAll(value.getPassangers());
}
}
List<TravelRequestDTO> result = new ArrayList<>(hashMap.values());
you can use the below code to get a List of TravelRequestDTO objects based on properties.
Function<TravelRequestDTO, List<Object>> compositeKey = travelRecord ->
Arrays.<Object>asList(travelRecord.getOnWard(),travelRecord.getReturn(),travelRecord.getLeavingFrom(),travelRecord.getGoingTo());
Map<Object, List<TravelRequestDTO>> map =
people.collect(Collectors.groupingBy(compositeKey, Collectors.toList()));

Java streams: Add to map but avoid mutation

I often find myself in a situation where I need to create a Map of objects from a Set or List.
The key is usually some String or Enum or the like, and the value is some new object with data lumped together.
The usual way of doing this, for my part, is by first creating the Map<String, SomeKeyValueObject> and then iterating over the Set or List I get in and mutate my newly created map.
Like the following example:
class Example {
Map<String, GroupedDataObject> groupData(final List<SomeData> list){
final Map<String, GroupedDataObject> map = new HashMap<>();
for(final SomeData data : list){
final String key = data.valueToGroupBy();
map.put(key, GroupedDataObject.of(map.get(key), data.displayName(), data.data()));
}
return map;
}
}
class SomeData {
private final String valueToGroupBy;
private final Object data;
private final String displayName;
public SomeData(final String valueToGroupBy, final String displayName, final Object data) {
this.valueToGroupBy = valueToGroupBy;
this.data = data;
this.displayName = displayName;
}
public String valueToGroupBy() {
return valueToGroupBy;
}
public Object data() {
return data;
}
public String displayName() {
return displayName;
}
}
class GroupedDataObject{
private final String key;
private final List<Object> datas;
private GroupedDataObject(final String key, final List<Object> list) {
this.key = key;
this.datas = list;
}
public static GroupedDataObject of(final GroupedDataObject groupedDataObject, final String key, final Object data) {
final List<Object> list = new ArrayList<>();
if(groupedDataObject != null){
list.addAll(groupedDataObject.datas());
}
list.add(data);
return new GroupedDataObject(key, list);
}
public String key() {
return key;
}
public List<Object> datas() {
return datas;
}
}
This feels very unclean. We create a map, and then mutate it over and over.
I've taken a liking to java 8s use of Streams and creating non-mutating data structures (or rather, you don't see the mutation). So is there a way to turn this grouping of data into something that uses a declarative approach rather than the imperative way?
I tried to implement the suggestion in https://stackoverflow.com/a/34453814/3478016 but I seem to be stumbling. Using the approach in the answer (the suggestion of using Collectors.groupingBy and Collectors.mapping) I'm able to get the data sorted into a map. But I can't group the "datas" into one and the same object.
Is there some way to do it in a declarative way, or am I stuck with the imperative?
You can use Collectors.toMap with a merge function instead of Collectors.groupingBy.
Map<String, GroupedDataObject> map =
list.stream()
.collect(Collectors.toMap(SomeData::valueToGroupBy,
d -> {
List<Object> l = new ArrayList<>();
l.add(d.data());
return new GroupedDataObject(d.valueToGroupBy(), l);
},
(g1,g2) -> {
g1.datas().addAll(g2.datas());
return g1;
}));
The GroupedDataObject constructor must be made accessible in order for this to work.
If you avoid the GroupedDataObject and simply want a map with a key and a list you can use Collectors.groupingBy that you have been looking into.
Collectors.groupingBy will allow you to do this:
List<SomeObject> list = getSomeList();
Map<SomeKey, List<SomeObject>> = list.stream().collect(Collectors.groupingBy(SomeObject::getKeyMethod));
This will require SomeKey to have proper implementations of equals and hashValue
Sometimes streams are not the way to go. I believe this is one of those times.
A little refactoring using merge() gives you:
Map<String, MyTuple> groupData(final List<SomeData> list) {
Map<String, MyTuple> map = new HashMap<>();
list.forEach(d -> map.merge(d.valueToGroupBy(), new MyTuple(data.displayName(), data.data()),
(a, b) -> {a.addAll(b.getDatas()); return a;});
Assuming a reasonable class to hold your stuff:
class MyTuple {
String displayName;
List<Object> datas = new ArrayList<>();
// getters plus constructor that takes 1 data and adds it to list
}

how to ignore null when deserializing from json string to object?

I have a class defined as below:
// Ignore all the unknown properties in input JSON
#JsonIgnoreProperties(ignoreUnknown = true)
// Only include non null values in deserialized Java object.
#JsonInclude(value = Include.NON_NULL)
public class Person {
#JsonProperty("person_id")
private String personId;
#JsonProperty("school")
private String school;
#JsonProperty("hobbies")
private Map<String, List<AttributeBag>> hobbies = new HashMap<String, List<AttributeBag>>();
#JsonProperty("tasks")
private Map<String, Map<String, AttributeBag>> tasks = new HashMap<String, Map<String, AttributeBag>>();
public Map<String, List<AttributeBag>> getHobbies() {
return hobbies;
}
public Person(String person_id, String school) {
super();
this.person_id = person_id;
this.school = school;
}
When I use a JSON string below to deserialize from string to object,
{
"person_id":"123",
"school":"stanford University"
}
From the object I got deserialized, the hobbies is create but empty, and the tasks is not created even. I am expecting the way like "tasks", if there is no corresponding field in JSON, it SHOULD NOT get deserialized in the object.
But the weird thing is : when I check object.getHobbies()!=null but the tasks part is null. I want both are null in the object if they were not present in JSON.
I have a constructor for the Person class but I did not initialize both hobbies and tasks part.
Thanks a lot
#JsonProperty("hobbies")
private Map<String, List<AttributeBag>> hobbies = new HashMap<String, List<AttributeBag>>();
#JsonProperty("tasks")
private Map<String, Map<String, AttributeBag>> tasks = new HashMap<String, Map<String, AttributeBag>>();
from above code its clear that you are creating new objects for hobbies and tasks no matter what, I am not able to understand why your tasks are not created(it should get created as a empty map)
and to answer your question #JsonInclude(value = Include.NON_NULL) should do the trick!
The JSON deserialiser will not attempt to set the fields that don't appear in the JSON structure, but these lines:
#JsonProperty("hobbies")
private Map<String, List<AttributeBag>> hobbies = new HashMap<String, List<AttributeBag>>();
#JsonProperty("tasks")
private Map<String, Map<String, AttributeBag>> tasks = new HashMap<String, Map<String, AttributeBag>>();
are creating the values on object construction.
If you want them to be null then don't allocate them in the object, just leave the declaration:
#JsonProperty("hobbies")
private Map<String, List<AttributeBag>> hobbies;
#JsonProperty("tasks")
private Map<String, Map<String, AttributeBag>> tasks;

how do i access an array by its key in java and also store the array in a hashmap

how do i access an array by its keys in java
In this case i want the structure to be like this,
options[{"value":"0","label":"zero"},{"value":"1","label":"one"},
{"value":"2","label":"two"}]
Here if i want to access options[1].value should give me 1 and options[2].label should give me two.
How can i achieve this with Map<string><string[]>?
Also Can i pass "options" array as one of the keys in my hash map
protected Map<String, String[]> getValueProperties(int view, Field field) {
Map<String, String> properties = new HashMap<String,String[]>();
properties.put("options", []);
return properties
}
You should create a new class representing your object:
public final class MyObject {
private String value;
private String label;
public MyObject(String label, String value) { ... }
public String getValue() { ... }
public String getLabel() { ... }
}
And then create a list of MyObject:
final List<MyObject> objects = new ArrayList<>();
objects.add(new MyObject("zero", "0");
objects.add(new MyObject("one", "1");
objects.add(new MyObject("two", "2");
Then you can access the objects values directly: objects.get(0).getValue();
Create a class as follows
class Entry
{
int value;
string label;
public Entry(int val, string lbl)
{
this.value = val;
this.label = lbl;
}
}
Now create you options array as follows:
Entry[] options = new Entry[3];
options[0] = new Entry(0, "zero");
options[1] = new Entry(1, "one");
options[2] = new Entry(2, "two");
if i want to access options[1].value should give me 1 and options[2].label should give me two
Now, options[1].value will give you 1.

Bind multiple elements to map with attribute as key with java XML annotations, JAXB

I have an XML source from which I unmarshall Objects with JAXB.
The XML source:
<album>
<name>something</name>
<id>003030</id>
<artist>someone</artist>
...
</album>
The java source is like (with the required getter/setters as well):
#XmlRootElement(name="album")
class Album {
String name;
Long id;
String artist;
...
}
So far so good. Now I get some image urls in different sizes within album list:
...
<image size="small">http://.../small.jpg</image>
<image size="medium">http://.../medium.jpg</image>
<image size="large">http://.../large.jpg</image>
...
I want to map it to a java Map something like this:
Map<String,String> imageUrls;
Where the map's key would be the size attribute and the map's value would be the element value.
If it's possible, how should I annotate this variable?
helper class Pair
#XmlAccessorType(XmlAccessType.FIELD)
public class Pair {
#XmlAttribute
private String key;
#XmlValue
private String value;
public Pair() {
}
public Pair(String key, String value) {
this.key = key;
this.value = value;
}
//... getters, setters
}
List of pairs
#XmlAccessorType(XmlAccessType.FIELD)
public class PairList
{
private List<Pair> values = new ArrayList<Pair>();
public PairList() {
}
//...
}
adaptor
public class MapAdaptor extends XmlAdapter<PairList, Map<String, String>>
{
#Override
public Map<String, String> unmarshal(PairList list) throws Exception
{
Map<String, String> retVal = new HashMap<String, String>();
for (Pair keyValue : list.getValues())
{
retVal.put(keyValue.getKey(), keyValue.getValue());
}
return retVal;
}
#Override
public PairList marshal(Map<String, String> map) throws Exception
{
PairList retVal = new PairList();
for (String key : map.keySet())
{
retVal.getValues().add(new Pair(key, map.get(key)));
}
return retVal;
}
}
usage in your entity
#XmlJavaTypeAdapter(value = MapAdaptor.class)
private Map<String, String> imageUrls = new HashMap<String, String>();
PS
You can do it without class PairList using Pair[] instead of PairList
adaptor
public class MapAdaptor extends XmlAdapter<Pair[], Map<String, String>>
{
#Override
public Map<String, String> unmarshal(Pair[] list) throws Exception
{
Map<String, String> retVal = new HashMap<String, String>();
for (Pair keyValue : Arrays.asList(list))
{
retVal.put(keyValue.getKey(), keyValue.getValue());
}
return retVal;
}
#Override
public Pair[] marshal(Map<String, String> map) throws Exception
{
List<Pair> retVal = new ArrayList<Pair>();
for (String key : map.keySet())
{
retVal.add(new Pair(key, map.get(key)));
}
return retVal.toArray(new Pair[]{});
}
}
but in this case you can't control name of every pair. It will be item and you can't change it
<item key="key2">valu2</item>
<item key="key1">valu1</item>
PS2
If you will try use List<Pair> instead of PairList, you will get Exception
ERROR: java.util.List haven't no-arg constructor

Categories

Resources