Display Hibernate Query in JTable - java

I'm seeking an efficient way to display an SQL table queried via Hibernate in a JTable.
Query q = em.createNamedQuery("Files.findAll");
List rl = q.getResultList();
It would probably be preferable to use the List returned by that (In this case, that would make a list of Files objects (where Files is an internal class, not java.io.File)), but I won't be picky as long as it is neat.
I have one answer I worked up below, but that doesn't work very well. I'd going to end up having to write a TableModel for it if I keep going down this path.

There are a lots and lots of ways to do this, but are you looking for something that would automatically figure out the columns or what? If you used the java reflection pieces you can read the Hibernate annotations to find out the column names and populate the JTable that way...
Otherwise this is just a straight forward piece of code that a. creates a JTable and TableModel, and b. populates the display with the database data.
EDIT:
I think this example may cover walking the annotation tree and processing them. The specifics are the AnnotationProcessorFactory part iirc.
EDIT 2:
I also found this library which is built to help lookup annotations at runtime. One of their examples is looking up Entity classes in hibernate to build a resource list - I believe you could do something similar to find classes that that implement #column, or #basic etc. This should allow you via reflection to pretty easily do it, but as I said java's standard library already provides the ability to walk the annotation tree to find out the column names - at which point creating the JTable from that should be very easy to do in a programmatic way.
EDIT 3:
This code is all that and a bag of chips! From here you should easily be able to walk the list of maps and pull out all of the info you want, the value, its class type, the field name for the column headers... Note that it isn't particularly safe.. I've dropped out all of the error code I did while testing to keep it short...
List<Map> createTable(List queryResults) {
List<Map> r = new LinkedList<Map>();
for (Object o : queryResults) {
r.add(entityMap(o));
}
return r;
}
Map entityMap(Object obj) throws Throwable {
Map m = new HashMap();
for (Field field : getFields(obj.getClass())) {
Method method = getMethod(field);
Object value = method.invoke(obj);
m.put(field, value);
}
return m;
}
List<Field> getFields(Class<?> clazz) {
List<Field> fields = new LinkedList<Field>();
for (Field field : clazz.getDeclaredFields()) {
Column col = field.getAnnotation(Column.class);
if (col != null)
fields.add(field);
}
return fields;
}
Method getMethod(Field field) throws NoSuchMethodException {
Class<?> clazz = field.getDeclaringClass();
String name = "get" + uppercase(field.getName());
Method method = clazz.getMethod(name);
return method;
}
String uppercase(String str) {
return str.substring(0,1).toUpperCase() + str.substring(1);
}

Did you take a look at the org.hibernate.metadata classes. These provide you metadata information about classes and collections. You can also make calls to SessionFactory.getClassMetadata(Class) to get the metadata information for the class in question.

In the answer below I expect that your HQL returns not a list of objects, but a list of arrays of necessary properties that you wish to show in JTable (i.e. that you're using so calling report queries).
In that case you can write simple TableModelAdapter that will be used as a TableModel for JTable.
public class TableModelAdapter extends AbstractTableModel{
private List<Object[]> list;
public TableModelAdapter(List<Object[]> aList){
list = aList;
}
public int getColumnCount() {
if (list == null){
return 0;
}
if (list.size() == 0){
return 0;
}
return list.get(0).length;
}
public int getRowCount() {
if (list == null){
return 0;
}
return list.size();
}
public Object getValueAt(int row, int column) {
if (list == null){
return null;
}
return list.get(row)[column];
}
}
If you have to return list of objects we can change the example and path throw properties via reflection instead of array.

Well, here's what I ended up doing for now:
//client-side class
public String[][] getFilesArray() {
List<Files> files = remote.getFiles();
String[][] x = new String[files.size()][];
for (int i = 0; i < files.size(); i++) {
x[i] = files.get(i).getStringArray();
}
return x;
}
//DAO class
public String[] getStringArray() {
return new String[] {
fileid.toString(),
name,
DateFormat.getInstance().format(timestamp),
status,
hash
};
}
public static String[] getColumnNames() {
return new String[] {
"Id",
"Name",
"Timestamp",
"Status",
"Hash"
};
}

JIDE Data Grids provides a HibernateTableModel that could provide the functionality you are looking for if you are happy to buy a third party library.

private void DataRetrive() {
DefaultTableModel tbl = (DefaultTableModel) jtblDataRet.getModel();
tbl.setRowCount(0);
try {
// call local method which was opensession
opensession();
if (!session.isOpen()) {
session = Hibernate_ut.getSession().openSession();
tx = session.beginTransaction();
String hQ = "From Student";
Query que = session.createQuery(hQ, Student.class);
List<Student> list = (List) que.list();
for (int i = 0; i < list.size(); i++) {
Vector vt = new Vector();
vt.add(0, list.get(i).getStudentName().toString());
vt.add(1, list.get(i).getStudentAddr().toString());
vt.add(2, list.get(i).getGrade().toString());
vt.add(3, list.get(i).getContact().toString());
tbl.addRow(vt);
}
}
} catch (HibernateException e) {
System.out.println(e);
e.printStackTrace();
tx.rollback();
}
}

Related

Fundamental misunderstanding of objects and attributes in Java

I'm sitting on an assignment for university and I'm at a point, where I fear I haven't really understood something fundamental in the concecpt of Java or OOP altogether. I'll try to make it as short as possible (maybe it's sufficient to just look at the 3rd code segment, but I just wanted to make sure, I included enough detail). I am to write a little employee management. One class within this project is the employeeManagement itself and this class should possess a method for sorting employees by first letter via bubblesort.
I have written 3 classes for this: The first one is "Employee", which contains a name and an ID (a running number) , getter and setter methods and one method for checking whether the first letter of one employee is smaller (lower in the alphabet) than the other. It looks like this:
static boolean isSmaller(Employee source, Employee target) {
char[] sourceArray = new char[source.name.length()];
char[] targetArray = new char[target.name.length()];
sourceArray = source.name.toCharArray();
targetArray = target.name.toCharArray();
if(sourceArray[0] < targetArray[0])
return true;
else
return false;
}
I tested it and it seems to work for my case. Now there's another class called EmployeeList and it manages the employees via an array of employees ("Employee" objects). The size of this array is determined via constructor. My code looks like this:
public class EmployeeList {
/*attributes*/
private int size;
private Employee[] employeeArray;
/* constructor */
public EmployeeList(int size) {
this.employeeArray = new Employee[size];
}
/* methods */
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
/* adds employee to end of the list. Returns false, if list is too small */
boolean add(Employee m) {
int id = m.getID();
if (id > employeeArray.length) {
return false;
} else {
employeeArray[id] = m;
return true;
}
}
/* returns employee at certain position */
Employee get(int index) {
return employeeArray[index];
}
/* Sets employee at certain position. Returns null, if position doesn't exist. Else returns old value. */
Employee set(int index, Employee m) {
if (employeeArray[index] == null) {
return null;
} else {
Employee before = employeeArray[index];
employeeArray[index] = m;
return before;
}
}
Now comes my real problem: In a third class called "employeeManagement" I am supposed to implement the sorting algorithm. The class looks like this:
public class EmployeeManagement {
private EmployeeList ml = new EmployeeList(3);
public boolean addEmployee(Employee e) {
return ml.add(e);
}
public void sortEmployee() {
System.out.println(ml.getSize()); // I wrote this for debugging, exactly here lies my problem
for (int n = ml.getSize(); n > 1; n--) {
for (int i = 0; i < n - 1; i++) {
if (Employee.isSmaller(ml.get(i), ml.get(i + 1)) == false) {
Employee old = ml.set(i, ml.get(i + 1));
ml.set(i+1, old);
}
}
}
}
The "println" before my comment returns "0" in console... I am expecting "3" as this is the size I gave the "EmployeeList" as parameter of the constructor within my "EmployeeManagement" class. Where is my mistake ? And how can I access the size of the object I created in the "EmployeeManagement" class (the "3") ? I'm really looking forward to your answers!
Thanks,
Phreneticus
You are not storing size in your constructor. Something like,
public EmployeeList(int size) {
this.employeeArray = new Employee[size];
this.size = size; // <-- add this.
}
Also, setSize isn't going to automatically copy (and grow) the array. You will need to copy the array, because Java arrays have a fixed length. Finally, you don't really need size here since employeeArray has a length.
The size variable you are calling is the class field. If you take a quick look at your code, the getter is getting the field (which is initialized as zero when created). The size you are using it. The good way of doing it would be to get the size of the array in the getter like this:
public int getSize() {
return employeeArray.length;
}
This would return the size of the array in the object.

Search an ArrayList for values in another ArrayList

I have two different ArrayList instances, one of type Container and one of type String. The first is a list of "banned goods" (strings) for a country, and the other is a list of containers on a ship. The ship travels through the country, and the containers are searched for the banned goods. If the container contains the banned goods, that container should be removed/deleted.
public Customs(String country)
{
countryName = country;
bannedGoods = new ArrayList<String>();
}
public Ship(String n, double weight)
{
emptyWeight = totalWeight = weight;
name = n;
containers = new ArrayList<Container>();
}
I already have a method in the Ship class that removes the container:
public void removeContainer(int i)
{
if(i >= 0 && i < containers.size()) {
Container r = containers.remove(i);
totalWeight = totalWeight - r.getWeight();
}
}
I am trying to create an method to inspect the ship for the containers. I want to use two for-loops for each of the arrays, but I can't seem to get it right! Can someone help me use the two loops to search the arrays? Additionally, I think that I will need to use an iterator (the remove function, specifically) in the loop, but that is also confusing for me. Should the iterator remove method replace the method I already wrote in class ship? Here is what I have:
public void inspect(Ship ship)
{
for (String good : bannedGoods) {
for (String con : containers) {
if (con.contains(good) {
container.remove();
}
}
}
And here is my attempt at the iterator:
for(String good : bannedGoods) {
Iterator<String> it = ship.containers.iterator();
while (it.hasNext())
if (ship.contains(good))
it.remove();
}
I don't think you need 2 for loops. You should iterate over banned goods & simply remove it from the containers.
Also, Assuming that containers list is of type string as this is mentioned in your fist line : I have two different arrayLists of the same type String
public void inspect(Ship ship, ArrayList<String> bannedGoods){
if (ship == null || bannedGoods == null || bannedGoods.isEmpty())
return;
for(String good : bannedGoods){
ship.containers.remove(good);
}
}
If, Containers is of type Container and it contains a list of containers(Arraylist of string) which is accessible via the method get_containers(), the following would work:
public void inspect(Ship ship, ArrayList<String> bannedGoods){
if (ship == null || bannedGoods == null || bannedGoods.isEmpty())
return;
for(String good : bannedGoods){
for(Container container : ship.containers){
container.get_containers().remove(good);
}
}
}
You can stick to the methods you are using at the moment. But keep in mind that you either need to use the iterator's remove method or not use iterators. So to use your remove method, either implement Iterable or simply use indexes instead of iterators:
for (int i = 0; i < bannedGoods.size(); i++)
{
for (int j = 0; j < containers.size();) // NOTE: no j++ here
{
Container c = containers.get(j);
if (c.contains(bannedGoods.get(i))
c.removeContainer(j);
else
j++; // only if you don't remove the container increment
// j - when removing the next element gets current
// index
}
}
You're actually pretty close, and you've done a good job of focusing on object-oriented programming principles while designing your classes. I think the things you need to focus on now are just being more careful with your types. Below are some suggested modifications to your classes (Container isn't shown, but I'm assuming it has a public boolean contains (String s) method that checks whether the container has a certain good s inside.
import java.util.*;
public class Ship implements Iterable<Container> {
private double emptyWeight, totalWeight, weight;
private String name;
private List<Container> containers = new ArrayList<Container>();
public Ship(String n, double weight) {
emptyWeight = totalWeight = weight;
name = n;
}
private void removeContainer(int i) {
if (i >= 0 && i < containers.size()) {
Container r = containers.remove(i);
totalWeight = totalWeight - r.getWeight();
}
}
public Iterator<Container> iterator() {
return new Iterator<Container> {
private index = 0;
private Container previous = null;
public boolean hasNext() {
return index < containers.size();
}
public Container next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
previous = containers.get(index++);
return previous;
}
public void remove() {
if (previous == null) {
throw new IllegalStateException();
}
removeContainer(containers.indexOf(previous));
previous = null;
}
};
}
}
I suggest keeping removeContainer within your Ship class since it's responsible for keeping track of how its weight changes when a container is removed. For the same reason, don't allow external classes to directly access its containers list. That way you can prevent other code from adding or removing values from that list without updating the weight correctly. I'd suggest making the containers list private, and expose an Iterator to allow users of the class to interact with the containers.
Within your Customs class, you'd use the Iterator's remove method to remove offending Container instances:
import java.util.*;
public class Customs {
private String countryName;
private List<String> bannedGoods = new ArrayList<String>();
public Customs(String country) {
countryName = country;
}
public void inspect(Ship ship) {
for (String good : bannedGoods) {
for (Iterator<Container> it = ship.iterator(); it.hasNext();) {
Container container = it.next();
if (container.contains(good) {
it.remove();
}
}
}
}
}

Setting Bean's properties with a loop

I have a class called Bean which has 3 fields
public class Bean {
private Object field0;
private Object field1;
private Object field2;
public Object getField0() {
return field0;
}
public void setField0(Object field0) {
this.field0 = field0;
}
public Object getField1() {
return field1;
}
public void setField1(Object field1) {
this.field1 = field1;
}
public Object getField2() {
return field2;
}
public void setField2(Object field2) {
this.field2 = field2;
}
I want to set each one of the fields with data to do so
int j, i;
for (j = 0; j < body.size(); j++) {
line = new Bean();
List row = body.get(j);
HashMap map = new HashMap(headers.length);
for (i = 0; i < headers.length; i++) {
line.choosefield2(i, headers, row);
}
list.add(line);
}
and choosefield2 is in the bean:
public void choosefield2(int i, String[] headers, List row) {
switch (i) {
case 0:
this.setField0(row.get(0));
break;
case 1:
this.setField1(row.get(1));
break;
case 2:
this.setField2(row.get(2));
break;
Can I do this in a for cycle instead of doing a case switch? I have way more than 3 fields so it's not really practical. I heard reflections might be an option. I wanted something like
for (i = 0; i < headers.length; i++) {
line.setField[i]=row.get(i);
}
list.add(line);
}
is this possible? Using JDK 1.6
You can, the question is, if you should. Of course you can dynamically search the methods and invoke them via reflection.
Class<?> clz = Bean.class;
Method[] methods = clz.getDeclaredMethods();
// etc.
methods[i].invoke( ... );
But this does NOT help you make your code more readable typically - and it will slow down your application. Also you of course lose much type-safety and compiler checking, potentially replacing many compiler errors with exceptions occuring during runtime. You should only do so if you have not other choices.
This sounds like an ideal task for Java 8:
// keep and reuse this list:
List<BiConsumer<Bean,Object>> setters=Arrays.asList(
Bean::setField0, Bean::setField1, Bean::setField2);
Bean bean;
List<Object> values;
assert setters.size()==values.size();
for(int i=0, num=setters.size(); i<num; i++)
setters.get(i).accept(bean, values.get(i));
This code does not use Reflection but rather an explicit list of defined properties, so you’ll notice errors at compile time already. But adding a new property is still as easy as adding Bean::setNewProperty to the list at the beginning…
The construction of all beans may look like:
List<List<?>> body;
List<Bean> beans=body.stream().map(row-> {
Bean bean=new Bean();
for(int i=0, num=setters.size(); i<num; i++)
setters.get(i).accept(bean, row.get(i));
return bean;
}).collect(Collectors.toList());
Apache commons-beanutils is a project that was created to make dealing with beans easier than using raw reflection. You could do something like this:
Map<String, String> properties = BeanUtils.describe(bean);
List<String> orderedProperties = new ArrayList<>(properties.keySet()); // cache in an instance variable
// sometime later...
BeanUtils.setProperty(obj, orderedProperties.get(i), value);
Just be careful about BeanUtils because I seem to remember it thinking getClass() was a property because it looks like a getter. You might want to check for a setter on each property that BeanUtils finds.

Simplifying a method design in java

Lets assume that I have a class with multiple String fields.
public class Person {
private String address;
private String first_name;
//etc
Now lets say that I have a List of Persons:
List<Person>
I want to write a method that can parse this list for a specific string value, e.g. address=="California".
The problem is that I have multiple fields in this class and it would be a lot of code reuse if I make a method for each field.
I could also do:
public List<Person> filter(List<Person> plist, String fieldToParse, String value){
//simple loop that removes the Person.fieldToParse == Person.value values
}
But is there a simpler, less ugly way for me to do this?
You could take a look at the lambdaj library (https://code.google.com/p/lambdaj/) if your goal is to filter the Person objects by a property. See this question/answer, as well What is the best way to filter a Java Collection?
You can use any LAMBDA library or you can implement it by yourself. See my code:
public static List<Person> filter(List<Person> source, String fieldToParse, String value) {
// Field getter
Method fieldGetter = null;
try {
fieldGetter = Person.class.getMethod("get" + firstUpperCase(fieldToParse));
} catch (NoSuchMethodException ex) {
throw new IllegalArgumentException("Invalid field name: " + fieldToParse);
}
// Filter
List<Person> list = new ArrayList<Person>();
for (Person person : source) {
try {
Object obj = fieldGetter.invoke(person);
//TODO: process NULL here
if (obj.equals(value)) {
list.add(person);
}
} catch (Exception e) {
}
}
return list;
}
public static String firstUpperCase(String str) {
if (str == null) {
return null;
}
if (str.isEmpty() == false) {
char[] chars = str.toCharArray();
chars[0] = Character.toUpperCase(chars[0]);
return new String(chars);
}
return str;
}
Sample uses:
filter ( source, "address", "abc");
filter ( source, "first_name", "july");
When you define a method like you suggested you lose the type safety (and some error detection in compile time).
This what will happen if someone will call this method with a filed string that does not exist?
To achieve this goal you can try to use Guava collections library.
There is a filter method in the Collection2 class that gets a predicate.
See http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Collections2.html.
You can provide a helper method that will create a predicate for a predefined set of fields if such filters will be common.

Difficulty understanding nested collections

I am working on dynamically generating classes in java using byte-code and then loading the class. I found this code on a tutorial how to do it.
private int stringConstant(String s) {
return constant(CONSTANT_Utf8, s);
}
private int classConstant(String s) {
int classNameIndex = stringConstant(s.replace('.', '/'));
return constant(CONSTANT_Class, classNameIndex);
}
private int constant(Object... data) {
List<?> dataList = Arrays.asList(data);
if (poolMap.containsKey(dataList))
return poolMap.get(dataList);
poolMap.put(dataList, poolIndex);
return poolIndex++;
}
private void writeConstantPool(DataOutputStream dout) throws IOException {
dout.writeShort(poolIndex);
int i = 1;
for (List<?> data : poolMap.keySet()) {
assert(poolMap.get(data).equals(i++));
int tag = (Integer) data.get(0);
dout.writeByte(tag); // u1 tag
switch (tag) {
case CONSTANT_Utf8:
dout.writeUTF((String) data.get(1));
break; // u2 length + u1 bytes[length]
case CONSTANT_Class:
dout.writeShort((Integer) data.get(1));
break; // u2 name_index
default:
throw new AssertionError();
}
}
}
private final Map<List<?>, Integer> poolMap =
new LinkedHashMap<List<?>, Integer>();
private int poolIndex = 1;
I don't understand how the map containing the list is being used it doesn't seem like a traditional oop way of doing this sort of thing.
In the fragment you've given us, the map is a means to assign a unique index (increasing from 1) to every List you put into it. This index is apparently only used in the assert to check that the keys are retrieved in the same order they are inserted - which should indeed be the case given that the map is a LinkedHashMap.
As far as the given code is concerned, a LinkedHashSet would have done as well. Of course we don't know where constant etc. are invoked, maybe the indices are used by the invoker.
I see no objections from an OO point of view - there is little OO about this code fragment in the first place.

Categories

Resources