Convert java List to object using collection -Stream - java

From the method List> method() i get the output like this with 3 elements
[123456, 10, 03-JAN-16]
[956233, 20, 03-JAN-16]
[254656, 30, 03-JAN-16]
[455556, 40, 04-JAN-16]
[548566, 50, 03-JAN-16]
[215663, 60, 03-JAN-16]
I need to store the above result in a pojo class name 'ClassName' which has the following columns col1, col2 and col3, So I try to run the following code as
public void method() {
try {
List<List<String>> list = testDAO.methodName();
List<ClassName> className= new ArrayList<ClassName>();
for (Iterator<List<String>> iterator = list.iterator(); iterator.hasNext();) {
List<String> list2 = (List<String>) iterator.next();
int i = 0;
ClassName className= new ClassName ();
for (Iterator<String> iterator2 = list2.iterator(); iterator2.hasNext();) {
String string = (String) iterator2.next();
/* System.out.println(string); */
if (i == 0)
className.setCol1(string);
else if (i == 1)
className.setCol2(Long.parseLong(string));
else if (i == 2)
className.setCol3(string);
i++;
}
odhs.add(className);
System.out.println(className);
// System.out.println(className.col2());
// System.out.println(className.col3());
}
// System.out.println("Total size: "+ odhs.size());
} catch (Exception e) {
e.printStackTrace();
}
}
But i got the output as
com.project.model.ClassName#61af1510
com.project.model.ClassName#37af1f93
com.project.model.ClassName#778d82e9
com.project.model.ClassName#408e96d9
com.project.model.ClassName#59901c4d
com.project.model.ClassName#168cd36b
com.project.model.ClassName#d8d9199
com.project.model.ClassName#3901f6af
Please provide a solution to save the datas in the POJO class 'ClassName'

Your class Odh must override the toString method.

On your Odh class you have to override toString method.
#Override
public String toString ( )
{
return "Odh [firstAttribute=" + firstAttribute + ", secondAttribute=" + secondAttribute + "]";
}

Override Odh's toString method.
Assuming the names of your parameters are dist_id,pv and post_date and all are of String types
#Override
public String toString(){
return getClass().getSimpleName() + "[dist_id=" + dist_id + ", pv=" + pv + ", post_date=" + post_date + "]";
}
That would allow you to print
Odh[dist_id=123456, pv=10, post_date=03-JAN-16]

Related

Java > Count occurrence of null and 0 in JSON Response

I have a JSON response. I need to count values that are null and then values that are 0. The JSON looks something like:
{
“stuffA“:{“a”: {“b”: 1.12343, “c”: “2019-01-29”, “d”: null } },
”stuffB”:{ "e":{}, "f":{}, "g":{}},
”stuffC”:[ {"h":{}},{"i":{}} ],
”stuffD”:[ {“j”:{}},{“k”:{}},{“l”:{}},{“m”:{}}],
}
I tried convert JSONObject to HashMap And look for frequency of null then 0 but doesn’t seem to work.
map = (Map<String,Object>) gson.fromJson(json, map.getClass());
int count1 = Collections.frequency(map.values(), null);
int count2 = Collections.frequency(map.values(), 0);
Am I going about this correctly or is there a more effective way?
boolean objectIsNull = yourJsonObject.isNull("stuffA");
you can try this inside a for
first add following dependency to your pom.xml
<dependency>
<groupId>com.github.wnameless.json</groupId>
<artifactId>json-flattener</artifactId>
<version>0.8.1</version>
</dependency>
first i transform json to a flat map object then count the count null and empty objects:
public class Solution {
public static void main(String[] args) {
String json = "{\n" +
" \"stuffA\":{\"a\": {\"b\": 1.12343, \"c\": \"2019-01-29\", \"d\": null } },\n" +
" \"stuffB\":{ \"e\":{}, \"f\":{}, \"g\":{}},\n" +
" \"stuffC\":[ {\"h\":{}},{\"i\":{}} ],\n" +
" \"stuffD\":[ {\"j\":{}},{\"k\":{}},{\"l\":{}},{\"m\":{}}]\n" +
"}";
System.out.println(countZeroAndNull(json));
}
public static long countZeroAndNull(String json) {
Map<String, Object> flattenJson = JsonFlattener.flattenAsMap(json);
int count = 0;
for (String s : flattenJson.keySet()) {
if (flattenJson.get(s) == null) {
count++;
} else if (flattenJson.get(s) instanceof LinkedHashMap) {
if (((LinkedHashMap) flattenJson.get(s)).size() < 1) {
count++;
}
}
}
return count;
}
}
it your example it prints 10 as output

How to improve a cumbersome comparison of 2 objects' fields

We have a program that compares thousands of pairs of Students by checking each field of the Student and counting the diffs:
class Student{
String name;
String address;
String biologyCourse;
.....
// about 100 other fields
}
And the counter POJO class:
class Counters{
long bothStudentsHaveName;
long onlyLeftHasName;
long onlyRightHasName;
......
// number of fields in Student * 3 (both, only left, only right)
}
Our compare function accepts 2 students plus the counters object and needs to scan the fields and update the relevant counters:
public void compareStudents(Student left, Student right, Counters counters){
if (!StringUtils.isEmpty(left.name) && !StringUtils.isEmpty(right.name) ){
counters.bothStudentsHaveName++;
} else if (StringUtils.isEmpty(left.name) && !StringUtils.isEmpty(right.name)){
counters.onlyRightHasName++;
} else if (!StringUtils.isEmpty(left.name) && StringUtils.isEmpty(right.name))){
counters.onlyLeftHasName++;
}
/// and now??
}
At this point, we can add 100s more triplets of if/else like the above - but we believe there should be a much easier way to do that.
Reflection can be an option or maybe X dimensions arrays, but can we somehow write the code so the comparison and counting will be much more generic?
I have solved your problem with one single loop. But here I'm assuming that naming convention for all the fields will be the same as described in your question. Here I am dynamically accessing the Student fields and updating Counter fields accordingly. Here is the complete solution:
Solution Class:
public class Solution {
public void compareStudents(Student left, Student right, Counter counter) throws Exception {
for (Field field : Student.class.getDeclaredFields()) {
Object leftValue = field.get(left);
Object rightValue = field.get(right);
String fieldName = field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
if(leftValue != null && rightValue != null) {
Field counterField = Counter.class.getDeclaredField("bothStudentsHave" + fieldName);
counterField.set(counter, (long) counterField.get(counter) + 1);
} else if (leftValue != null) {
Field counterField = Counter.class.getDeclaredField("onlyLeftHas" + fieldName);
counterField.set(counter, (long) counterField.get(counter) + 1);
} else if (rightValue != null) {
Field counterField = Counter.class.getDeclaredField("onlyRightHas" + fieldName);
counterField.set(counter, (long) counterField.get(counter) + 1);
}
}
}
}
Student Class:
class Student {
String name;
String address;
String biologyCourse;
}
Counter Class:
class Counter {
// name
long bothStudentsHaveName;
long onlyLeftHasName;
long onlyRightHasName;
// address
long bothStudentsHaveAddress;
long onlyLeftHasAddress;
long onlyRightHasAddress;
// biologyCourse
long bothStudentsHaveBiologyCourse;
long onlyLeftHasBiologyCourse;
long onlyRightHasBiologyCourse;
// ... and so on
#Override
public String toString() {
return "Counter{" + "\n" +
"\tbothStudentsHaveName = " + bothStudentsHaveName + "\n" +
"\t, onlyLeftHasName = " + onlyLeftHasName + "\n" +
"\t, onlyRightHasName = " + onlyRightHasName + "\n" +
"\t, bothStudentsHaveAddress = " + bothStudentsHaveAddress + "\n" +
"\t, onlyLeftHasAddress = " + onlyLeftHasAddress + "\n" +
"\t, onlyRightHasAddress = " + onlyRightHasAddress + "\n" +
"\t, bothStudentsHaveBiologyCourse = " + bothStudentsHaveBiologyCourse + "\n" +
"\t, onlyLeftHasBiologyCourse = " + onlyLeftHasBiologyCourse + "\n" +
"\t, onlyRightHasBiologyCourse = " + onlyRightHasBiologyCourse + "\n" +
'}';
}
}
Tester Class:
public class Tester {
public static void main(String[] args) throws Exception {
// Creating Dummy Variables
Student student1 = new Student();
student1.name = "Test";
student1.biologyCourse = "Yes";
Student student2 = new Student();
student2.name = "Test1";
student2.address = "abc street";
Counter counter = new Counter();
// Comparing Students
Solution solution = new Solution();
solution.compareStudents(student1, student2, counter);
// Printing Counter
System.out.println(counter);
}
}
Output:
Counter{
bothStudentsHaveName = 1
, onlyLeftHasName = 0
, onlyRightHasName = 0
, bothStudentsHaveAddress = 0
, onlyLeftHasAddress = 0
, onlyRightHasAddress = 1
, bothStudentsHaveBiologyCourse = 0
, onlyLeftHasBiologyCourse = 1
, onlyRightHasBiologyCourse = 0
}
If you keep repreating the same basic pattern of fields, then consider extracting that into a class. For example introduce a FieldComparison class that looks a little like this:
public class FieldComparisonCounter {
public int bothHave;
public int onlyLeftHas;
public int onlyRightHas;
// constructor, getters, setters left as an exercise for the reader
}
Then have a Map<String,FieldComparisonCounter> counters somewhere and a method like this:
public void compareField(String fieldName, String leftValue, String rightValue) {
FieldComparisonCounter counter = counters.get(fieldName);
if (counter == null) {
counter = new FieldComparisonCounter();
counters.put(fieldName, counter);
}
boolean leftHas = !StringUtils.isEmpty(leftValue);
boolean rightHas = !StringUtils.isEmpty(rightValue);
if (leftHas && rightHas) {
counter.bothHave++;
} else if (leftHas) {
counter.onlyLeftHas++;
} else if (rightHas) {
counter.onlyRightHas++;
}
}
Then adding a new field comparison is as simple as calling
compareField("name", left.name, right.name);

Issue with returning all values

I am having trouble trying to return all the values in my Register class. Currently it only returns BLOGGS, J but should return JONES, F and SINGH, N also. Thank you in advance.
public static String execute(Register reg, Name n) {
reg.removeName(1);
reg.addName(n);
for (Name nm : reg) {
if(nm.getFamilyName().length() >= 5) {
return (nm.getFamilyName().toUpperCase() + ", " + nm.getFirstName().charAt(0) + "\n");
}
return null;
}
}
Here is the test code for the jUnit test
#Test
public void testExecute() {
Register r = new Register();
r.addName(new Name("Joe", "Bloggs"));
r.addName(new Name("Fred", "Jones"));
r.addName(new Name("Nila", "Singh"));
String result = RegisterApp.execute(r, new Name("Cassie", "Downturn"));
String expectedResult = "BLOGGS, J\nSINGH, N\nDOWNTURN, C\n";
assertEquals("The string returned should match the expected result (run 1)", expectedResult, result);
}
As #Carcigenicate already called out, you're returning right away from your for loop.
You could take advantage of stream api here:
public static String execute(Register reg, Name n) {
reg.removeName(1);
reg.addName(n);
return
reg.stream()
.filter(nm -> nm.getFamilyName().length() >= 5)
.map(nm -> nm.getFamilyName().toUpperCase() + ", " + nm.getFirstName().charAt(0) + "\n")
.collect(Collectors.joining());
}

set an array of enum

I have a little helper util that reads a csv into a pojo. For the most part it works really fine. Now I have an issue with enums.
I am able to fill:
an enum
a list of enums
an array
But I have a problem with an array of enums. Here is a code snippet of some of these special cases:
public void fillPojo(Object pojo) {
// use setter/getter as well - using beanutils
for(PropertyDescriptor pd : PropertyUtils.getPropertyDescriptors(pojo.getClass())) {
if(pd.getName().equals("class")|| pd.getReadMethod() == null)
continue;
// get the value (based on the property name)
String value = this.get(pd.getName());
if(value == null || value.equals("null"))
continue;
try {
// this works for normal lists and list of any enum
if(pd.getPropertyType().isAssignableFrom(List.class)) {
List<String> values = new ArrayList<>();
for(String s : value.split(","))
values.add(s);
pd.getWriteMethod().invoke(pojo, ConvertUtils.convert(values, pd.getPropertyType()));
}
else if(pd.getPropertyType().isArray()) {
///////////////////////// this throws a conversionException
List<String> values = new ArrayList<>();
for(String s : value.split(","))
values.add(s);
Object[] objs = new Object[values.size()];
for(int i = 0; i < objs.length; i++) {
if(StringUtils.isBlank(values.get(i)))
objs[i] = null;
else {
objs[i] = ConvertUtils.convert(values.get(i), pd.getPropertyType().getComponentType());
}
}
pd.getWriteMethod().invoke(pojo, objs);
/////////////////////////
}
else
if(pd.getPropertyType().isEnum()) {
if(StringUtils.isEmpty(value) || "null".equalsIgnoreCase(value))
pd.getWriteMethod().invoke(pojo, (Object)null);
else
pd.getWriteMethod().invoke(pojo, Enum.valueOf(pd.getPropertyType().asSubclass(Enum.class), value));
}
else
pd.getWriteMethod().invoke(pojo, ConvertUtils.convert(value, pd.getPropertyType()));
} catch (NullPointerException | IllegalAccessException | IllegalArgumentException
| ConversionException | InvocationTargetException e) {
System.err.println("'" + pojo.getClass().getSimpleName() + "' Problem while setting: " + pd.getName() + " with value " + value + " type: " + pd.getPropertyType().getSimpleName() + ":" + e.getMessage());
e.printStackTrace();
}
}
I tried different approaches to create the enum, but I cannot seem to be able to correctly create a list of enums and setting them without throwing an exception.
Seems you pass into the setter an array of invalid type, e.g. you have bean setter:
public void setMyEnumArray(MyEnum[] array) {...}
then your call of 'pd.getWriteMethod().invoke(pojo, objs)' would be similar to:
Object[] objs = new Object[values.size()];
...
pojo.setMyEnumArray(objs);
Thus, you should convert Object[] into MyEnum[] before calling this setter:
Object[] objs = new Object[values.size()];
...
objs = Arrays.copyOf(objs, objs.length, (Class) pd.getPropertyType());
pd.getWriteMethod().invoke(pojo, objs);

Java compare two map

In java, I want to compare two maps, like below, do we have existing API to do this ?
Thanks
Map<String, String> beforeMap ;
beforeMap.put("a", "1");
beforeMap.put("b", "2");
beforeMap.put("c", "3");
Map<String, String> afterMap ;
afterMap.put("a", "1");
afterMap.put("c", "333");
//--- it should give me:
b is missing, c value changed from '3' to '333'
I'd use removeAll() functionality of Set to to do set differences of keys to find additions and deletions. Actual changes can be detected by doing a set difference using the entry set as HashMap.Entry implements equals() using both key and value.
Set<String> removedKeys = new HashSet<String>(beforeMap.keySet());
removedKeys.removeAll(afterMap.keySet());
Set<String> addedKeys = new HashSet<String>(afterMap.keySet());
addedKeys.removeAll(beforeMap.keySet());
Set<Entry<String, String>> changedEntries = new HashSet<Entry<String, String>>(
afterMap.entrySet());
changedEntries.removeAll(beforeMap.entrySet());
System.out.println("added " + addedKeys);
System.out.println("removed " + removedKeys);
System.out.println("changed " + changedEntries);
Output
added []
removed [b]
changed [c=333]
The Guava Maps class has some methods for calulating the differences between a pair of maps. However, these methods give you a data structure representing the differences not a pretty-printed string.
There isn't any out of the box component to help with that. You'll probably have to code it unfortunately. The good news is the logic is pretty easy.
Depending upon your particular needs, you might also consider using other applications designed to do this work, like diff. You could write the two maps to two different files, and diff the files.
String output = new String();
for (String key:beforeMap.getKeys()){
String beforeValue = beforeMap.getValue(key);
String afterValue = afterMap.getValue(key);
//nullsafe
if(beforeValue.equals(afterValue){}
else if (afterValue == null){
output = output + key + " is missing, ";
continue;
}else {
output = output + key + " has changed from " + beforeValue + " to " + afterValue + " , ";
}
afterMap.remove(key);
}
for (String key:afterMap.getKeys()){
output = output + key + " was added with value " + afterMap.getValue(key) + ", ";
}
if(output == null){
output = "Same map";
}
output = output.substring(0,output.length-2);
System.out.println(output);
You could use a custom object that contains the key and the value (actually Map does this internally, hidden from the user, so we can't use that)
Put these tuples into a Set
To compare two sets, convert them both to arrays, sort the arrays and walk both arrays from begin to end in parallel, stepping down the first array if it's key is smaller than the key in the second array, and vise versa.
class Tuple implements Comparable<Tuple>
{
public String key;
public String value;
public Tuple(String key, String value)
{
this.key = key;
this.value = value;
}
#Override
public int compareTo(Tuple o)
{
return key.compareTo(o.key);
}
}
public static void main(String[] args)
{
// TreeSet is already sorted. If you use HashSet, use Arrays.sort()
Set<Tuple> beforeSet = new TreeSet<>();
beforeSet.add(new Tuple("a", "1"));
beforeSet.add(new Tuple("b", "2"));
beforeSet.add(new Tuple("c", "4"));
Set<Tuple> afterSet = new TreeSet<>();
afterSet.add(new Tuple("a", "1"));
afterSet.add(new Tuple("c", "333"));
afterSet.add(new Tuple("aa", "4"));
Tuple[] beforeArray = beforeSet.toArray(new Tuple[beforeSet.size()]);
Tuple[] afterArray = afterSet.toArray(new Tuple[afterSet.size()]);
int beforePtr = 0;
int afterPtr = 0;
while (beforePtr < beforeArray.length || afterPtr < afterArray.length)
{
int difference = afterPtr >= afterArray.length? -1 : beforePtr >= beforeArray.length? 1 : beforeArray[beforePtr].compareTo(afterArray[afterPtr]);
if (difference == 0)
{
if (!beforeArray[beforePtr].value.equals(afterArray[afterPtr].value))
{
System.out.println(beforeArray[beforePtr].key + " value changed from '" + beforeArray[beforePtr].value + "' to '" + afterArray[afterPtr].value + "'");
}
beforePtr++;
afterPtr++;
}
else if (difference < 0)
{
System.out.println(beforeArray[beforePtr].key + " is missing");
beforePtr++;
}
else
{
System.out.println(afterArray[afterPtr].key + " is added");
afterPtr++;
}
}
}
#user595234 To Compare the two Maps you can add the keys of a map to list and with those 2 lists you can use the methods retainAll() and removeAll() and add them to another common keys list and different keys list. Using the keys of the common list and different list you can iterate through map, using equals you can compare the maps.
public class Demo
{
public static void main(String[] args)
{
Map<String, String> beforeMap = new HashMap<String, String>();
beforeMap.put("a", "1");
beforeMap.put("b", "2");
beforeMap.put("c", "3");
Map<String, String> afterMap = new HashMap<String, String>();
afterMap.put("a", "1");
afterMap.put("c", "333");
System.out.println("Before "+beforeMap);
System.out.println("After "+afterMap);
List<String> beforeList = getAllKeys(beforeMap);
List<String> afterList = getAllKeys(afterMap);
List<String> commonList1 = beforeList;
List<String> commonList2 = afterList;
List<String> diffList1 = getAllKeys(beforeMap);
List<String> diffList2 = getAllKeys(afterMap);
commonList1.retainAll(afterList);
commonList2.retainAll(beforeList);
diffList1.removeAll(commonList1);
diffList2.removeAll(commonList2);
System.out.println("Common List of before map "+commonList1);
System.out.println("Common List of after map "+commonList2);
System.out.println("Diff List of before map "+diffList1);
System.out.println("Diff List of after map "+diffList2);
if(commonList1!=null & commonList2!=null) // athough both the size are same
{
for (int i = 0; i < commonList1.size(); i++)
{
if ((beforeMap.get(commonList1.get(i))).equals(afterMap.get(commonList1.get(i))))
{
System.out.println("Equal: Before- "+ beforeMap.get(commonList1.get(i))+" After- "+afterMap.get(commonList1.get(i)));
}
else
{
System.out.println("Unequal: Before- "+ beforeMap.get(commonList1.get(i))+" After- "+afterMap.get(commonList1.get(i)));
}
}
}
if (CollectionUtils.isNotEmpty(diffList1))
{
for (int i = 0; i < diffList1.size(); i++)
{
System.out.println("Values present only in before map: "+beforeMap.get(diffList1.get(i)));
}
}
if (CollectionUtils.isNotEmpty(diffList2))
{
for (int i = 0; i < diffList2.size(); i++)
{
System.out.println("Values present only in after map: "+afterMap.get(diffList2.get(i)));
}
}
}
/** getAllKeys API adds the keys of the map to a list */
private static List<String> getAllKeys(Map<String, String> map1)
{
List<String> key = new ArrayList<String>();
if (map1 != null)
{
Iterator<String> mapIterator = map1.keySet().iterator();
while (mapIterator.hasNext())
{
key.add(mapIterator.next());
}
}
return key;
}
}
The below code will give you this output:
Before: {b=2, c=3, a=1}
After: {c=333, a=1}
Unequal: Before- 3 After- 333
Equal: Before- 1 After- 1
Values present only in before map: 2

Categories

Resources