I have a resultset (returned by a stored procedure) like -
I need a List of HashMap, and HashMap will be made of individual (distinct by combination of FirstName, LastName and Id) students records. Below image will describe the structure of HashMap.
So, basically in this example, I need a list of 3 HashMap.
Can you please suggest some efficient way to do that? Thanks!
why do I need a list of hashmap for this?
I need to create an XML file out of this ResultSet. List of HashMap is the best way I can think of for required XML structure.
XML Structure :
If my approach is not correct in terms of coding standard or efficiency, please suggest me different approach.
What I am thinking:
I've not tried yet. But can not think anything else other than iterating over the ResultSet and temporarily storing FirstName, LastName and Id to check if it is same as previous value or not. If same then add marks array to MarksList, else consider it as record of another student. I am hoping there might be a different way.
[Update]:
I think I should use list of Objects, not list of HashMap. But the question still is, how can I interpret the value from resultset and set values into the object.
UPDATE
Provided code to extract the data from the ResultSet correctly into the objects used by JAXB.
You don't need a HashMap and/or a List of HashMap to create a xml file
You can do this easily with JAXB, provided you create the correct data objects.
First, create classes to match the structure desired to be in the xml.
a ScoreRecord class which holds the course information such as course name and mark.
a Student class which holds student info such as firstname, lastname and a list of ScoreRecords objects.
a StudentGroup class which holds all the students belonging to the same faculty group
The ScoreRecord class:
import java.math.BigDecimal;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlRootElement(name = "Mark")
#XmlType(propOrder = { "sub", "percent" })
public class ScoreRecord {
private String sub;
private String percent;
public void setSub(String sub) {
this.sub = sub;
}
public String getSub() {
return sub;
}
public void setPercent(String percent) {
this.percent = percent;
}
public String getPercent() {
return percent;
}
}
The Student class:
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlRootElement(name = "Student")
#XmlType(propOrder = { "firstName", "lastName", "id", "scoreRecords" })
public class Student {
private Integer id;
private String firstName;
private String lastName;
private List<ScoreRecord> scoreRecords;
public void setId(Integer id) {
this.id = id;
}
#XmlElement(name = "Id")
public Integer getId() {
return id;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#XmlElement(name = "FirstName")
public String getFirstName() {
return firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
#XmlElement(name = "LastName")
public String getLastName() {
return lastName;
}
public void setScoreRecords(List<ScoreRecord> scoreRecords) {
this.scoreRecords = scoreRecords;
}
#XmlElementWrapper(name = "MarksList")
#XmlElement(name = "Mark")
public List<ScoreRecord> getScoreRecords() {
return scoreRecords;
}
}
The StudentGroup class:
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "Records")
public class StudentGroup {
private List<Student> students;
public void setStudents(List<Student> students) {
this.students = students;
}
#XmlElement(name = "StudentRecord")
public List<Student> getStudents() {
return students;
}
}
Now, create a class to hold the data "as is" from the database
public class DbStudent {
private String firstName;
private String lastName;
private Integer id;
private String sub;
private String percent;
public DbStudent(String firstName, String lastName, int id, String sub, String percent) {
this.firstName = firstName;
this.lastName = lastName;
this.id = id;
this.sub = sub;
this.percent = percent;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getFirstName() {
return firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getLastName() {
return lastName;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
public void setSub(String sub) {
this.sub = sub;
}
public String getSub() {
return sub;
}
public void setPercent(String percent) {
this.percent = percent;
}
public String getPercent() {
return percent;
}
}
Create a method to retrive the data as a List of this object type. I assume you already have something that gets the ResultSet, iterate it and .add to the list of DbStudent objects.
Something like:
public List<DbStudent> getStudents() throws ClassNotFoundException, SQLException {
List<DbStudent> entries = new ArrayList<DbStudent>();
Class.forName(databaseDriver);
this.connection = DriverManager.getConnection(connectionString);
Statement sttm = this.connection.createStatement();
ResultSet rs = sttm.executeQuery("select * from TMP_STUDENT"); //in your case procedure call
if (rs != null) {
while (rs.next()) { //add the results into the list
entries.add(new DbStudent(rs.getString("FIRSTNAME"), rs.getString("LASTNAME"), rs.getInt("ID"),
rs.getString("SUB"), rs.getString("PERCENT")));
}
rs.close();
}
return entries;
}
Now, the main method. It contains logic to extract all the info from the list of database objects. Basically we sort it by id, iterate through it checking if we find or not a new student. If we find a new student, we add the previous one to a list of Student objects. This student already has his marks set.
public static void main(String[] args) throws JAXBException {
//get the data from the database as is
OracleConnection myOracleConnection = new OracleConnection(ORACLE_DRIVER, ORACLE_CONN);
List<DbStudent> dbStudentList = null;
try {
dbStudentList = myOracleConnection.getStudents(); //get the list of students from the procedure or query
myOracleConnection.CloseConnection();
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.out.println("Stopping execution and exiting...");
System.exit(-1);
} catch (SQLException e) {
e.printStackTrace();
System.out.println("Stopping execution and exiting...");
System.exit(-1);
}
//sort the list on Id, so we can know when we find a new student
Collections.sort(dbStudentList, new Comparator<DbStudent>() {
public int compare(DbStudent s1, DbStudent s2) {
return s1.getId().compareTo(s2.getId());
}
});
List<Student> studentList=new ArrayList<Student>(); //list which will hold all the student objects
Integer previousId = 0; //control variable
List<ScoreRecord> marksList = new ArrayList<ScoreRecord>(); //list to store the marks for each student
Student s = null;
for (int i=0;i<dbStudentList.size();i++) {
if(i==dbStudentList.size()-1){ //if we reached the end, no more students after this record, set the marks and add the student to the list
s.setScoreRecords(marksList);
studentList.add(s);
}
if (dbStudentList.get(i).getId().compareTo(previousId) != 0) {
//new student found
if(s!=null){
//if new student found add the previous one to the list after setting the marks
s.setScoreRecords(marksList);
studentList.add(s);
}
s = new Student(); //create a new student
s.setFirstName(dbStudentList.get(i).getFirstName());
s.setId(dbStudentList.get(i).getId());
s.setLastName(dbStudentList.get(i).getLastName());
ScoreRecord sr = new ScoreRecord();
sr.setSub(dbStudentList.get(i).getSub());
sr.setPercent(dbStudentList.get(i).getPercent());
marksList = new ArrayList<ScoreRecord>(); //reset marks list
marksList.add(sr);
} else {
//same student
ScoreRecord sr = new ScoreRecord();
sr.setSub(dbStudentList.get(i).getSub());
sr.setPercent(dbStudentList.get(i).getPercent());
marksList.add(sr); //add mark to existing marks list
}
previousId=dbStudentList.get(i).getId(); //set the control variable to the new id
}
StudentGroup sg=new StudentGroup(); //create the student wrapper
sg.setStudents(studentList); //add the student list to the wrapper
//create xml with JAXB
JAXBContext context = JAXBContext.newInstance(StudentGroup.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
m.marshal(sg, new File(STUDENT_XML));
}
The output of the xml is exactly how you want it:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Records>
<StudentRecord>
<FirstName>AA1</FirstName>
<LastName>BB1</LastName>
<Id>1</Id>
<MarksList>
<Mark>
<sub>Math</sub>
<percent>51%</percent>
</Mark>
<Mark>
<sub>Phy</sub>
<percent>61%</percent>
</Mark>
<Mark>
<sub>Bio</sub>
<percent>61%</percent>
</Mark>
</MarksList>
</StudentRecord>
<StudentRecord>
<FirstName>AA2</FirstName>
<LastName>BB2</LastName>
<Id>2</Id>
<MarksList>
<Mark>
<sub>Bio</sub>
<percent>62%</percent>
</Mark>
</MarksList>
</StudentRecord>
<StudentRecord>
<FirstName>AA3</FirstName>
<LastName>BB3</LastName>
<Id>3</Id>
<MarksList>
<Mark>
<sub>Math</sub>
<percent>53%</percent>
</Mark>
<Mark>
<sub>Phy</sub>
<percent>63%</percent>
</Mark>
<Mark>
<sub>Chem</sub>
<percent>63%</percent>
</Mark>
</MarksList>
</StudentRecord>
</Records>
What you need here is correct Data object. Here it should Student record which internally should hold the list of score records
which will have id,FirstName , LastName, scoreRecords(it should be list holding subject name, marks, % etc).
Then simply convert it into XML with JAXB
If you sort your sql-statement/storedprocedure by LastName and FirstName you don't need to collect the whole data in memory.
Simply iterate your resultset and collect the data until FirstName and LastName changes, than aggregate your sub and percent data and stream it directly to a file or a dom. And so on....
Or change the stored procedure or create a new one in that way that it already aggregates the data for you.
Related
So for example.
I have an ArrayList of people. Created through a people object that contains a name, address, age, etc.
How would I then add another list to that, allowing a unique list of hobbies for each person?
So I could have:
James, 32, England, (Football, Tennis)
Chloe, 21, Wales, (Art)
Tried a few things and struggling with it.
import java.util.ArrayList;
public class People {
int id;
String name;
ArrayList<String> hobbies;
public People(int id, String name, ArrayList<String> hobbies) {
this.id = id;
this.name = name;
this.hobbies = hobbies;
}
public People(String name) {
this.name = name;
}
public People() {
// TODO Auto-generated constructor stub
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "People [id=" + id + ", name=" + name + ", hobbies=" + hobbies + "]";
}
}
import java.util.ArrayList;
public class Runner {
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<People> arrayPeople = new ArrayList<>();
ArrayList<String> hobbies = new ArrayList<>();
hobbies.add("Football");
hobbies.add("Tennis");
arrayPeople.add(new People(1,"Paul", hobbies));
hobbies.add("Golf");
arrayPeople.add(new People(2,"James", hobbies));
System.out.println(arrayPeople);
}
}
This creates a hobby list that is the same for each person, not unique.
This creates a hobby list that is the same for each person, not unique.
That's because member hobbies in [Paul] People object has same value as member hobbies in [James] People object, since they are assigned the same value in method main of class Runner. Hence when you change hobbies variable, in method main of class Runner, you are changing for both Paul and James.
The simplest solution is to change the class constructor so that it creates a copy of the hobbies parameter and assigns the copy to the hobbies member:
public People(int id, String name, List<String> hobbies) {
this.id = id;
this.name = name;
this.hobbies = new ArrayList<>(hobbies);
}
However, I suggest that you add methods to class People to manipulate hobbies member, including:
addHobby for adding a hobby
removeHobby for removing a hobby
clearHobbies for removing all hobbies
getHobbies that returns a copy of hobbies (so that code that calls the method cannot change hobbies)
Below code demonstrates.
Note that you should always use the interface – in this case java.util.List – rather than the implementation – in this case ArrayList – in the API so that you can change class People without having to change its API. If you change the API of class People then all other classes that use class People – like class Runner in the code in your question – will need to be changed as well.
import java.util.ArrayList;
import java.util.List;
public class People {
private int id;
private String name;
private List<String> hobbies;
public People(int id, String name, List<String> hobbies) {
this.id = id;
this.name = name;
this.hobbies = new ArrayList<>(hobbies);
}
public People(int id, String name) {
this(id, name, new ArrayList<String>());
}
public People() {
this(0, "");
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void addHobby(String hobby) {
if (!hobbies.contains(hobby)) {
hobbies.add(hobby);
}
}
public void clearHobbies() {
hobbies.clear();
}
public List<String> getHobbies() {
return List.of(hobbies.toArray(new String[]{}));
}
public void removeHobby(String hobby) {
if (hobbies.contains(hobby)) {
hobbies.remove(hobby);
}
}
#Override
public String toString() {
return "People [id=" + id + ", name=" + name + ", hobbies=" + hobbies + "]";
}
public static void main(String[] args) {
List<People> arrayPeople = new ArrayList<>();
People paul = new People(1,"Paul");
paul.addHobby("Football");
paul.addHobby("Tennis");
People james = new People(2,"James");
james.addHobby("Football");
james.addHobby("Tennis");
james.addHobby("Golf");
arrayPeople.add(paul);
arrayPeople.add(james);
System.out.println(arrayPeople);
}
}
Running the above code prints the following:
[People [id=1, name=Paul, hobbies=[Football, Tennis]], People [id=2, name=James, hobbies=[Football, Tennis, Golf]]]
The question seemed unclear to me, however I assume that you created lists such as
[name,age,location]
However, this is not an object. If you create a person object, you can add features inside it. So that when you create a person object, then you will have access to add/edit new features. In your case, your features must be:
Name
Age
Location
List (Whatever you name it, type of it must be an arraylist).
To have a list of people:
class Person{
String name;
int age;
String Address;
...
}
and
ArrayList<Person>
For the people class, if you need each hobby in hobbies to be unique you can have a Set class to store hobbies.
class Person{
String name;
int age;
String address;
Set<String> hobbies;
...
}
If the order does not matter you can use HashSet To maintain the order you can use TreeSet or LinkedHashSet.
class person{
String name;
int age;
String address;
TreeSet<String> hobbies;
...
}
class Person{
String name;
int age;
String address;
LinkedHashSet<String> hobbies;
...
}
To add a hobby to a person.
String hobby = "a hobby";
person.add(hobby);
To add hobbies to a person;
String hobby1 = "hobby1";
String hobby1 = "hobby2";
...
Set<String> hobbies = new TreeSet(); // or Set<String> hobbies = new LinkedHashMap();
hobbies.add(hobby1);
hobbies.add(hobby2);
...
person.addAll(hobby);
For another person with the same hobbies, you need to copy the hobbies, then modifying the hobbies of the second person will not affect the hobbies of the first person.
Set<String> new_hobbies = new TreeSet(old_hobbies); // or new LinkedHashSet(old_hobbies);
another_person.addAll(new_hobbies);
Here I have used two ConcurrentHashMaps,
1st map: key = name
value = Employee obj (containing 2nd map)
2nd map: key = id
value = Employee details( pojo class)
But I m doing it wrong. pls someone explain what should be my approach.
here is my code -
import java.util.concurrent.ConcurrentHashMap;
public class POJODemo {
public static void main(String[] args)
{
ConcurrentHashMap <String, Employee> outer_concurrentHashMap = new ConcurrentHashMap<String,Employee>();
Employee empobj = new Employee();
empobj.setId("123");
outer_concurrentHashMap.put("disha", empobj.toString());
System.out.println(outer_concurrentHashMap);
}
}
class Employee
{
public static ConcurrentHashMap <String , POJODetails> inner_concurrentHashMap = new ConcurrentHashMap <String , POJODetails>();
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
POJODetails details = new POJODetails("korba", 12345);
}
class POJODetails{
public POJODetails(String address, int phone) {
super();
this.address = address;
this.phone = phone;
}
private String address;
private int phone;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getPhone() {
return phone;
}
public void setPhone(int phone) {
this.phone = phone;
}
public String toString()
{
return ;
}
}
'outer_concurrentHashMap.put("disha", empobj.toString());' is incorrect; should be 'outer_concurrentHashMap.put("disha", empobj);'
You cannot convert your object to a string and put it in a hash map that only takes employee as a value. When you print the Map it will call.toString on the employee and still print it visibly for you.
When you created your HashMap, you specified that it would take an object of type String as a 'key' and an object of type Employee as a 'value'.
Using HashMap.get('key'), will return an object of type Employee, which is the mapped value to your key. So you could write:
Employee retrievedEmployee = outer_concurrentHashMap.get("disha");
//'retrievedEmployee' has the same value as 'empobj'
In your code, when you write:
outer_concurrentHashMap.put("disha", empobj.toString());
you are not adding an object of type Employee to your hashmap, but the representation of that object as a string.
The correct code would be:
outer_concurrentHashMap.put("disha", empobj);
I am trying to use OpenCSV to parse a CSV file into a list of objects so I can load student data into my Student Team Allocator system.
I have been following this guide under the heading 'Parsing the records into a Java Object'
After some issues with dependencies I have it outputting a list of Student objects, however the CSV columns are not bound to the member fields as they should be. Print test returns null values for every object's fields.
I have two constructors in Student, one that initialises the 3 fields, and one that is empty. I know currently the empty one gets used as removing this one causes InstantiationExceptions in the Student object.
CSVParser Class
public class CSVParser {
private static String CSV_FILE_PATH;
public CSVParser(String CSVPath){
CSV_FILE_PATH = CSVPath;
try (
Reader reader = Files.newBufferedReader(Paths.get(CSV_FILE_PATH));
) {
ColumnPositionMappingStrategy strategy = new ColumnPositionMappingStrategy();
strategy.setType(Student.class);
String[] memberFieldsToBindTo = {"fName", "sName", "stuNumber"};
strategy.setColumnMapping(memberFieldsToBindTo);
CsvToBean csvToBean = new CsvToBeanBuilder(reader)
.withMappingStrategy(strategy)
.withSkipLines(1)
.withIgnoreLeadingWhiteSpace(true)
.build();
List<Student> Students = csvToBean.parse();
for (Student s : Students) {
System.out.println("First Name : " + s.getFirstName());
System.out.println("Second Name : " + s.getSecondName());
System.out.println("StudentNo : " + s.getStudentNumber());
System.out.println("---------------------------");
}
} catch (IOException ex) {
Logger.getLogger(CSVParser.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Student Class
public class Student {
private String fName;
private String sName;
private String stuNumber;
private String skill;
private final String[] skills = {"Planning","Writing","Developing"};
public Student(){
}
public Student(String fName, String sName, String stuNumber) {
this.fName = fName;
this.sName = sName;
this.stuNumber = stuNumber;
}
// Setters
public void setSkill(int skillIndex){
this.skill = skills[skillIndex];
}
public void setFirstName(String fName){
this.fName = fName;
}
public void setSecondName(String sName){
this.sName = sName;
}
public void setStudentNumber(String stuNumber){
this.stuNumber = stuNumber;
}
// Getters
public String getFirstName(){
return fName;
}
public String getSecondName(){
return sName;
}
public String getStudentNumber(){
return stuNumber;
}
// Save to Database
private void saveStudent(){
// DBConnect db = new DBConnect();
}
}
The exception caused by non empty constructor
The print test showing null values in Student fields
Please let me know how I can make things any clearer,
Thanks.
The names in the column mapping array should respond to the names of the setters rather than the fields themselves. If it can't find a setter that correspond to the name, it can't set the value.
I am newbie in java and I have a method that accepts 3 parameters, query the db and returns result in an arraylist form (like this [1, Java, 3, Bangalore, 10] ). How can i extract individual element so that I can assign each to a var like int id=1;String name=Java.
Below is the method that
ArrayList searchResult =jSearch.doJobSearch(techName, exp, city);
Iterator searchResultIterator = searchResult.iterator();
PrintWriter out = response.getWriter();
String arrayList[] = new String[searchResult.size()];
if(searchResultIterator.hasNext()){
for(int i =0; i<searchResult.size(); i++){
//searchResult.get(i)
out.println(searchResult.get(i));
}
}else{
out.println("No Job found in selected city");
}
ArrayList works in the sense of [index, element].
By using the get method, you're using index as the parameter and it returns the element at that position. So if you're accessing the element by it's index you already have both the id and element, but a different collection interface might suit you better like a map.
http://docs.oracle.com/javase/7/docs/api/java/util/Map.html
Create POJO (Plain Old Java Object). I am providing example how to array list is used when store Real time Object.
package com.appkart.examples;
public class Employee {
private int id;
private String name;
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
And Add Employee into Array list and get values
package com.appkart.examples;
import java.util.ArrayList;
public class Program {
public static void main(String[] args) {
ArrayList<Employee> employees = new ArrayList<Employee>();
Employee arun = new Employee(10, "Arun");
Employee ankit = new Employee(20, "Ankit");
Employee jon = new Employee(30, "Jon");
Employee anil = new Employee(40, "Anil");
employees.add(arun);
employees.add(ankit);
employees.add(jon);
employees.add(anil);
for (Employee employee : employees) {
int id = employee.getId();
String name = employee.getName();
System.out.println("id : "+id +" name : "+name);
}
}
}
the psuedo for what im trying to do is
-send Array of EMPLOYEE objects to Restaurant Class
-In Class RESTAURANT give each of the employee objects a name and last name (last name not in employee Class but in PERSON Class which Employee CLass Extends.
-print say employeeList[1].getLastName()
hopefully my code explains better
class Person {
public Person(final String last) {
}
}
class Employee extends Person {
private String firstName;
// getFirstName method
// getLastName Method
Employee(final String first, final String last) {
super(last);
}
}
class Restaurant { // set first object in array have first and last name
public void setFirstLast(final Employee[] employeeList) {
String firstName = "Jovana";
String lastName = "Valdez";
employeeList[0] = new Employee(firstName, lastName); // set up via constructor
}
}
public class Main {
private String lastName;
public static void main(final String[] args) {
Employee[] employeeList = new Employee[1]; // my array of Employee objects, all set to null
Restaurant restaurant = new Restaurant();
restaurant.setFirstLast(employeeList);
}
}
from main when i try to print System.out.printf("first is %d\n",arrayList.getFirst()); i get null for the value as well as the value for the last name so what is the correct way to go about and set values to objects in the array?
Edit arrayList initialized in Class restaurant by
public Table[] create_table_array(Table table,int number) {
Table[] TableList = new Table[number];
int i = 0;
for(i = 0; i < number; i++) {
TableList[i] = table;
}
return TableList;
Your constructor doesn't save firstName, it should look like:
Employee(String first, String last) {
super(last);
firstName = first;
}
You did not make good constructor of Person class and it class does not have instance variable lastName in which you should assign value you get in constructor as a parameter.
Also constructor of Employee does not assign any value to firstName.
What ArrayList ?As i see you are working with arrays?I didn't see it in code anywhere?
System.out.printf("first is %d\n",**arrayList**.getFirst());so command is wrong.
Any code that has meaning to me and can be compilled is to fix those things and delete formatting options you putted in System.out.printf because you are not formatting numbers.
So code look like :
class Person {
String lastName;
public Person(final String last) {
lastName=last;
}
}
class Employee extends Person {
private String firstName;
public String getFirstName()
{return firstName;}
public String getLastName()
{return lastName;}
Employee(final String first, final String last) {
super(last);
firstName=first;
}
}
class Restaurant { // set first object in array have first and last name
public void setFirstLast(final Employee[] employeeList) {
String firstName = "Jovana";
String lastName = "Valdez";
employeeList[0] = new Employee(firstName, lastName); // set up via constructor
}
}
public class Main {
private String lastName;
public static void main(final String[] args) {
Employee[] employeeList = new Employee[1];
Restaurant restaurant = new Restaurant();
restaurant.setFirstLast(employeeList);
System.out.printf("first is "+employeeList[0].getFirstName()+" "+employeeList[0].getLastName());
}
}