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.
Related
I have a Object which contains a list of another object which contains a list of another object and so on... suppose I want to get count of nested list elements(lets say last one), what should be best approach rather than using traditional for loop in java as I have done in below example -
public static void main(String[] args) {
Statement statement = new Statement();
statement.getInvAccount().add(new InvestmentAccount());
statement.getInvAccount().get(0).getSecAccountStmt().add(new SecurityStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
// method to count the number of TransactionStatement
System.out.println("Size of TransactionStatement is : " + count(statement));
}
private static int count(Statement stmt) {
int countOfTransStmt = 0;
for (InvestmentAccount invAcc : stmt.getInvAccount()) {
if (invAcc != null) {
for (SecurityStatement secStmt : invAcc.getSecAccountStmt()) {
if (secStmt != null) {
countOfTransStmt = countOfTransStmt + secStmt.getTransactionStatement().size();
}
}
}
}
return countOfTransStmt;
}
In Java 7 you're not going to do better than two for loops. I wouldn't bother with anything different.
In Java 8 you can use streams to flatten it out:
private static int count(Statement stmt) {
return stmt.getInvAccount().stream()
.filter(Objects::nonNull)
.flatMap(InvestmentAccount::getSecAccountStmt)
.filter(Objects::nonNull)
.flatMap(SecurityStatement::getTransactionStatement)
.count();
}
I would encourage you to get rid of the null checks. If you're going to ignore nulls, better to just expect them not to be inserted in the first place. It'll get rid of a lot of extra if checks throughout your code, I expect.
I'd also encourage you not to abbreviate your variables and methods. Spell out "statement" and "investment" and the like. The abbreviations are harder to read and the brevity isn't really a win.
Similarly, try to use more descriptive method names. countTransactions is better for the main method. And for the various getters, methods that return lists ought to be plural: "getAccounts" rather than "getAccount". Notice how the getters now match the class names; if you know the class name, you know the getter name. You don't have to guess if one or the other is abbreviated:
private static int countTransactions(Statement statement) {
return statement.getInvestmentAccounts().stream()
.flatMap(InvestmentAccount::getSecurityStatements)
.flatMap(SecurityStatement::getTransactionStatements)
.count();
}
Recursion could work in this case:
General idea below:
private int countTransactions(object t)
{
int sum = 0;
if (t == null) return 0;
for (int i = 0; i < t.getAllSub().count; i++)
{
sum += countTransactions(t.subAt(i));
}
return sum;
}
Is there a way to use getter method as a variable, I mean in here i want to replace getDiscountCode() with a variable
for (int row=0; row < pOSBean.getItemList().size(); row++) {
valueDTO = new ValueDTO();
valueDTO.setRowId(1);
valueDTO.setValue(pOSBean.getItemList().get(row).getDiscountCode());
valueListDTO.add(valueDTO);
}
something like this
variable = getDiscountCode();
for (int row=0; row < pOSBean.getItemList().size(); row++) {
valueDTO = new ValueDTO();
valueDTO.setRowId(1);
valueDTO.setValue(pOSBean.getItemList().get(row).+variable);
valueListDTO.add(valueDTO);
}
i can't use 'pOSBean.getItemList().get(row).getDiscountCode()' row as a variable cuz rowid is there
any Suggestions plz
public List<ItemCartDTO> getItemList() {
return itemList;
}
public class ItemCartDTO implements Serializable {
private String locCode;
private List<CommonDropdownItemsDTO> selectedItmStockList;
private String discountCode;
public String getDiscountCode() {
return discountCode;
}
public void setDiscountCode(String discountCode) {
this.discountCode = discountCode;
}
...
}
You can use the functional interface Function for that purpose:
Function<Integer, DISCOUNT_CODE> method = (row) -> pOSBean.getItemList().get(row).getDiscountCode(); // Edit DISCOUNT_CODE Type
The Function will take a Integer (your row) and return the discount code:
valueDTO.setValue(method.apply(row));
You may also look into the enhanced for loop. With that type of loop you can make your loop even prettier:
for (Item item : pOSBean.getItemList())
{
valueDTO = new ValueDTO();
valueDTO.setRowId(1);
valueDTO.setValue(item.getDiscountCode());
valueListDTO.add(valueDTO);
}
There are some important details missing. For example, when you call valueDTO.setValue(...), what type does setValue expect? Any Object? A String? Some custom class? If it's a custom class, are there really multiple getters that you could vary between, that would return that class?
Say setValue's parameter is an Object. If getRow() returns something of class YourClass, you can write:
Function<YourClass, Object> getter = YourClass::getDiscountCode;
and call it like this:
valueDTO.setValue(getter.apply(pOSBean.getItemList().get(row)));
I have this class that serves as a container which I will use the instance variable for processing later
class Data{
static int counter= 0;
boolean boolean1;
String string1;
public Data() {
counter++;
}
}
And I have this method that sets the values of Data
public Data setData()
{
Data data = null;
for (int i = 0; i < somecoutnerhere; i++) {
Data = new Data();
Data.boolean1 = some boolean put here;
Data.string1 = "some string to be put here";
}
return ProcessData(Data);
}
I also have this class ProcessData that will make use of Data and will construct the response
private class ProcessData
{
private final Map<String, List<?>> map = new HashMap<String, List<?>>();
int counter;
public ProcessData(Data data)
{
map.put("boolean1", data.boolean1);
map.put("String1", data.string1);
counter = data.counter;
}
public String someMethodToGenerateReturnData(){
// some code here to make use of the Data collected. Will basically use map to construct the return String
}
}
My problem is that I couldn't figure out how can I return all the instance variables created on the for-loop for Data on setData(). Any thoughts?
My problem is that I couldn't figure out how can I return all the instance variables created on the for-loop for Data on setData(). Any thoughts?
According to this your problem is not "returning all instance one variables in one call", as your title states, but rather a question about how returning all Data-Objects created in your for-loop, which is easier.
Your code is erronous though, so I went ahead & corrected it (I hope I didn't mess up). I also renamed a few things.
The changes I made are:
renamed "boolean1" and "string1" to "trueOrFalse" and "string"
added a public, fully parameterized constructor to the Data-class
added a ProcessData-list to the setData()-method, which is filled in the for-loop
(+ a comment)
However, I'd strongly recommend you to check your architecture, and also to learn a bit about naming conventions, or coding conventions in general. Names should point out the purpose or content of the method/variable/class, and "boolean1" isn't really doing that.
Regarding the architecture: The Data-class seems to exist solely for the counter, and you could easily change that, making the Data-class obsolete (unless it's used somewhere else).
Data class:
class Data {
static int counter = 0;
boolean trueOrFalse;
String string;
public Data() {
counter++;
}
public Data(boolean someBoolean, String someString) {
this.trueOrFalse= someBoolean;
this.string = someString;
counter++;
}
}
setData()-Method:
public List<ProcessData> setData() {
List<ProcessData> processedDataList = new ArrayList<ProcessData>();
for (int i = 0; i < someCounterHere; i++) {
processedDataList.add(new ProcessData(new Data(true, "testString"));
// a new Data-object is created (parameters true and "testString")
// a new ProcessData-object is created (parameter is the newly created Data-Object)
// the newly created ProcessData-object is added to the list
}
return processedDataList;
}
ProcessData-class:
private class ProcessData {
private final Map<String, List<?>> map = new HashMap<String, List<?>>();
int counter;
public ProcessData(Data data) {
map.put("trueOrFalse", data.trueOrFalse);
map.put("string", data.string);
counter = data.counter;
}
public String someMethodToGenerateReturnData() {
// some code here to make use of the Data collected. Will basically use map to construct the return String
}
}
if (a != 1 && solone == (int)solone && soltwo == (int)soltwo){
// (lx+o)(mx+p)
int h = (a*c);
List<Integer> factors = new ArrayList<Integer>();
for (int i = 1; i < Math.sqrt(h); i++) {
if (h % i == 0)
factors.add(i);
}
Integer result = null;
for (int ii: factors) {
if (b == ii + h/ii){
result = ii;
// ax^2+hiix+iix+c
}
int hii = h/ii;
int gcd1 = Euclid.getGcd(a, hii);
int gcd2 = Euclid.getGcd(ii, c);
String Factored = FactoredForm.getFF(gcd1, gcd2, a, hii);
}
My String called Factored is one I need to use for printing later in my code. I can't use it because it doesn't recognize the variable outside of the for loop. How do I go about making it public? When i added public in front of the string, it said that only final is permitted? Also, I cannot simply move the extraneous code outside of the for loop because it all depends on the integer "ii" which is part of the loop. Help!
Do you really want this to be part of the state of an instance of the class? If so, declare it outside the method:
private string factored;
public void Whatever(...)
{
factored = FactoredForm.getFF(gcd1, gcd2, a, hii);
}
I would advise you not to make it public. If you need to expose the value, do so via a property.
Think carefully about whether it really is logically part of the state of this class though. Also revisit naming conventions, as mentioned before.
public attribute is not related to a local variable but to an instance variable.
Inside the same function declarations follow two rules:
the order of declaration: if a local variable hasn't been declared yet, then you can't use it.
the scoping: if a variable has been declared inside a scope ({ ... }) then you can't access it from outside the scope.
If you want to access the variable later in the code you should declare it before the loop:
String factored;
if (....) {
....
....
factored = whatever;
}
System.out.println(factored);
or have it as an instance variable (meaningless, since it's a local that you need to print but whatever):
class FooBar
{
String factored;
void method() {
...
...
if (...) {
...
...
factored = whatever;
}
System.out.println(factored);
}
}
or thirdly you can return the variable from the method and use it somewhere else:
class FooBar
{
String method() {
...
...
if (...) {
...
...
return whatever;
}
return null;
}
void otherMethod() {
String factored = method();
System.out.println(factored);
}
}
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();
}
}