Using JDBC, I have managed to run a query on a database and receive a result set (rs). Using this information, I hope to generate a nested array list.
// Created Array List
public static ArrayList<ArrayList<SessionRecord>> tempSessionOrg = new ArrayList<ArrayList<SessionRecord>>();
The inner list needs to be grouped by the information returned from the first column. And this is all I've got thus far:
while(rs.next()) {
SessionRecord temp = new SessionRecord(rs.getString("SessionID"),rs.getString("NetworkAddress"),rs.getString("EventType"),rs.getString("Time"),rs.getString("Name"),rs.getString("SessionType"),rs.getString("ProcessType"));
}
I've already written a very similar program, with the exception that it places the result set into a single ArrayList without nesting. Unfortunatley, this analagous piece of code hasn't really helped me come up with a solution.
while(rs.next()) {
dbSession.add(new SessionRecord(rs.getString("name"),rs.getString("ParticipantName"),rs.getString("GuestLoggedOnUsername"),rs.getString("GuestMachineName"),rs.getString("inicio"),rs.getString("diferencia")));
}
Any suggestions?
EDIT:
At this point, I have the following two blocks one code.
One:
public static ArrayList<SessionRecord> singleSessionRecords = new ArrayList<SessionRecord>();
public static ArrayList<ArrayList<SessionRecord>> tempSessionOrg = new ArrayList<ArrayList<SessionRecord>>();
Two:
while(rs.next()) {
singleSessionRecords.add(new SessionRecord(rs.getString("SessionID"),rs.getString("NetworkAddress"),rs.getString("EventType"),rs.getString("Time"),rs.getString("Name"),rs.getString("SessionType"),rs.getString("ProcessType")));
}
Map<String, List<SessionRecord>> byID = singleSessionRecords.stream().collect(Collectors.groupingBy(SessionRecord::SessionID));
tempSessionOrg.add((ArrayList<SessionRecord>) Map.values());
I'm receiving a type mismatch error for the Map line and that I can't make a static reference to a non-static method in the final line. The later of the two is easy enough of a fix for me, but I'm not sure how to implement the Map properly.
Are you using Java 8?
If so this could easily be achieved by this code :
Map<String, List<SessionRecord>> byName
= temp.stream()
.collect(Collectors.groupingBy(SessionRecord::name));
In this example I'm grouping the sessionRecords by name, you can easily change this to fit your grouping needs.
Related
I've been using theories before to try different entries for how to set values for an object in jUnit.
Now I am facing this issue,
I want to do the same using theories and create different objects with all the possible answers but THEN group them all in a list to later pass other test (assertions).
I tried to make an empty list and add elements by calling a private method that runs with a theory and uses the entry points but doesnt work... like this:
#DataPoints("ids")
public static String[] eventIds = {"123", "1234"};
#Theory
private Object test(#FromDataPoints("ids") final String id) {
return new Object(id);
}
and then
#Test
private void finalTest() {
List<Object> objects = new ArrayList<Object>();
objects.add(test()); //<==== CANNOT DO THIS
}
any idea how to archive this?
At the end I want to get a List with all possible objects (in this case only 2)
So I have three important factors, filenames which there are many, there will also be duplicates, violation types which there are 6 of, and the data relating to them.
I was thinking of using a Map for this but it only accepts two types, so I want to sort the data by the filename and for every entry under that filename, i want to retrieve the violation type, from what i want it to retrieve all the matches from the data, so say it's a map I could of said map.get(filename, violation) and it will retrieve all the results that match that.
Is there a data structure that can allow me to do this? or am I being lazy and should just sort the data myself when it comes to outputting it.
One other way to approach this would be to use a custom Class for holding the needed data. Essentially 'building' your own node that you can iterate over.
For example! you could create the following class object: (Node.java)
import java.util.*;
public class Node
{
private String violationType;
private String dataInside;
public Node()
{
this("", "");
}
public Node(String violationType)
{
this(violationType, "");
}
public Node(String violationType, String dataInside)
{
this.violationType = violationType;
this.dataInside = dataInside;
}
public void setViolationType(String violationType)
{
this.violationType = violationType;
}
public void setDataInside(String dataInside)
{
this.dataInside = dataInside;
}
public String getViolationType()
{
return violationType;
}
public String getDataInside()
{
return dataInside;
}
}
ok, great, so we have this 'node' thing with some setters, some getters, and some constructors for ease of use. Cool. Now lets see how to use it:
import java.util.*;
public class main{
public static void main(String[] args){
Map<String, Node> customMap = new HashMap<String, Node>();
customMap.put("MyFilename", new Node("Violation 1", "Some Data"));
System.out.println("This is a test of the custom Node: " + customMap.get("MyFilename").getViolationType());
}
}
Now we have a map that relates all of the data you need it to. Now, you'll get a lot of people saying 'Don't reinvent the wheel" when it comes to things like this, because built in libraries are far more optimized. That is true! If you can find a data structure that is built into java that suits your needs, USE IT. That's always a good policy to follow. That being said, if you have a pretty custom situation, sometimes it calls for a custom approach. Don't be afraid to make your own objects like this, it's easy to do in Java, and it could save you a lot of time and headache!
EDIT
So, after re-reading the OP's question, I realize you want an entire list of associated data for the given violation of a given filename. In which case, you would switch the private String dataInside to something like private ArrayList<String> dataInside; which would allow you to associate as much data as you wanted, still inside that node, just inside of an arraylist. Also note, you'd have to switch up the getters/setters a little to accomodate a list, but that's not too bad.
You could use a custom class for a mapkey which contains the two fields filename and violation type. When doing so you need to implement equals() and hashCode() methods do ensure instances of that class can be used as key for map.
You can use TreeMap. TreeMap is sorted according to the natural ordering of its keys.
TreeMap<String, List<String>> map = new TreeMap<String, List<String>>();
Please be patient with the newbie question as I'm trying to learn MyBatis and java at the same time. I have an application in which I need to use threadsafe variables. Based on some research and my ideas of how the application will be used, I've settled on a CopyOnWriteArrayList over a Vector.
When I call a selectList from the mybatis sql session, is there any way to tell it to create an CopyOnWriteArrayList as its return rather than an ArrayList? Admittedly, my code to configure this is two lines instead of one, but something in me says that there's got to be a better way and/or I'm not the first one to have encountered this.
List<Team> teams = session.selectList("getTeamsByGameID", gameID);
List<Team> arrayListReturn = new CopyOnWriteArrayList<Team>(teams);
return arrayListReturn;
Thanks in advance,
I know of two ways to handle this.
Option 1: Use a Mapper class and specify the type of List to return there.
Define a Mapper interface:
public interface TeamMapper {
CopyOnWriteArrayList<Team> getTeamsByGameID();
}
Your mapper xml file stays the same. The code to do the query changes to:
TeamMapper m = session.getMapper(TeamMapper.class);
List<Team> lt = m.getTeamsByGameID();
System.out.println(lt.getClass());
//=> prints out "class java.util.concurrent.CopyOnWriteArrayList"
Option 2: Create a ResultHandler and pass that into the session.select() method.
Here you use the ResultHandler interface. That interface requires you to override one method, handleResult, which is given each result that comes back from the database as the query is in progress.
In your case, your ResultHandler would look something like this:
public class TeamResultHandler implements ResultHandler {
private List<Team> teams = new CopyOnWriteArrayList<Team>();
#Override
public void handleResult(ResultContext rc) {
countries.add((Team) rc.getResultObject());
}
// provide a getter so you can retrieve it when finished
public List<Team> getTeamList() {
return teams;
}
}
Instead of using selectList as you do above, you would now use the session.select(String, ResultHandler), like so:
TeamResultHandler rh = new TeamResultHandler();
session.select("getTeamsByGameID", rh);
List<Team> lt = rh.getTeamList();
return lt;
This solution is more verbose than your solution (requires an extra class and three lines in your query code, rather than 2), but it only creates one List, rather than two, so you'll have to decide which fits your needs best.
In addition, ResultHandlers can be useful for additional things - making sure results are sorted in a certain way or filtered or something else, in case you need that.
I am having difficulty accessing some data. I am using YCSB to talk to a number of different databases, such as Cassandra and MongoDB.
The only class I can really modify is my "Workload" class, which is doing some insertions and reads. The method I am using to read from the database is in the class:
public void doRead(DB db)
{
String keyname = buildKeyName(keynum);
System.out.println(keyname);
HashSet<String> fields = null;
if (!readallfields)
{
// read a random field
String fieldname = "field" + fieldchooser.nextString();
fields = new HashSet<String>();
fields.add(fieldname);
}
db.read(table,keyname,fields,new HashMap<String,ByteIterator>());
}
I tried to modify the code so I could read the contents of the hashmap. I removed the db.read line and replaced it with
HashMap<String, ByteIterator> kv_hashmap = new HashMap<String, ByteIterator>();
db.read(table, keyname, fields, kv_hashmap);
Then tried to read from kv_hashmap:
System.out.println(kv_hashmap.get(fields));
BUT db.read returns only an int. DB is a public abstract class which I would rather not modify and its purpose is to talk to a variety of databases:
This is what db.read calls:
public abstract int read(String table, String key, Set<String> fields, HashMap<String,ByteIterator> result);
Which returns, to quote from the javadoc:
Zero on success, a non-zero error code on error or "not found".
I need to read the values from kv_hashmap. I don't understand why I can't access its values.
I took a look at the implementation of the DB class and the javadoc additionally says:
#param result A HashMap of field/value pairs for the result
But, I then also looked at BasicDB which extends DB - and its body simply prints out the fields passed in.
What I suggest you do is print the actual concrete class of DB being passed into your method and see what that class is actually doing inside the read method, something like:
System.out.println(Test.class.getName());
Then take a look at the read method of whatever class is shown - if its not populating the result HashMap (as with the BasicDB implementation) then there wont be anything for you to read
EDIT: The entire code and database creation script can be found from http://gitorious.org/scheator . The database script is in Schema/.
I have the following Java code:
A LinkedHashMap defined in an abstract class as
LinkedHashMap<Object, Data> list;
A descendant class that initializes this list like this:
list = new LinkedHashMap<Integer, Data>();
I add items like this:
String id = rs.getString(FIELDS[0]);
String name = rs.getString(FIELDS[1]);
Data team = new Data(Integer.parseInt(id.trim()), name);
list.put(id, team);
Now when I do this:
System.err.println("delete() count: " + list.size());
System.err.println("delete() key value " + key);
Data obj;
obj = (Data)list.remove(key);
deletedList.put(key, obj);
System.err.println("delete() count: " + list.size());
Nothing is removed from the list, i.e. the first and last prints print the same size(). The key is also correct (I have verified there is an item by that id).
However, and this is my question, if I add the values like this:
Integer id = rs.getInt(FIELDS[0]);
String name = rs.getString(FIELDS[1]);
Data team = new Data(id, name);
list.put(id, team);
The code works! Shouldn't parseInt() produce a similar key to getInt()? Why does the second version work but the first doesn't? I spent a good hour debugging this until I found the reason and I still can't figure out the reason.
First example:
String id = rs.getString(FIELDS[0]);
Second example:
Integer id = rs.getInt(FIELDS[0]);
I can't say for sure since I can't see the rest of the code, but if the key variable is an Integer in this call:
obj = (Data)list.remove(key);
then the remove will only work if the object was put into the map using an Integer and that is why it is only working when the id is integer when you call the put method. The String "123" does not equal the integer 123.
Also I am assuming that you just missed a line in your first example but there was no call to list.put(id, team) but that could also be the source of your problems
There should be no difference, but there are a number of things that are not clear from your example:
deletedList does not refer to the list object
the records in your database that are being used are the same in both cases (perhaps in the first a different int is being used that is already in the Map)
Autoboxing may also be complicating the issue. Replace Integer id in the second sample with int id to pass the same arguments to your Data constructor.
Maybe you could post up the complete code such that we can reproduce the scenario accurately?
Update
You are using String values as keys in your original code. You then have an Object key in your remove(key) method, so I expect you are passing an Integer to the method at this point. A String will not match an Integer as a key, which explains why your remove was not working.
If you use generics to specify your HashMap (LinkedHashMap<Integer, Team> instead of <Object, Team>) this kind of error can't happen - the compiler will say something like
The method put(Integer, Object) in the type HashMap<Integer,Object> is not applicable for the arguments (String, String)
Yanamon is right. It's pretty clear when you look at the diff:
while (rs.next()) {
- String id = rs.getString(FIELDS[0]);
+ Integer id = rs.getInt(FIELDS[0]);
String name = rs.getString(FIELDS[1]);
- Data team = new Data(Integer.parseInt(id.trim()), name);
+ Data team = new Data(id, name);
list.put(id, team);
Note that in the original version, an int (auto-boxed to Integer) is being passed into the Data constructor. But id, which is being putted, is still a String.
My guess is that int the second case you cast it explicitly into an Integer
Integer id = rs.getInt(FIELDS[0]);
while on the first case it remains an int
Integer.parseInt(id.trim())
from the javadoc of parseInt
static int parseInt(String s)
Parses the string argument as a signed decimal integer.
If I were you I would inspect the contents of the LinkedHashMap using a debugger, before and after your put and before and after your remove. Step into the remove() method (the source code is part of the JDK) and see what it is doing. Odds are your code is not adding or removing the object correctly. It's hard to see here because the code sample is incomplete.
As for rs.getInt() and Integer.parseInt(), the first is database-vendor specific (I assume rs is a ResultSet), and thus they may not have the same behaviour. However, once the Integer key is created (you can verify this with your debugger) it should be equivalent for HashMap or LinkedHashMap purposes. But your code sample complicates things further; you are using rs.getString() and then Integer.parseInt(). While I would be surprised if this happened, it's possible that the database driver is formatting the id column into a string that confuses parseInt(). To me it's far more readable to just do rs.getInt().