This is an automated email from the ASF dual-hosted git repository.
doebele pushed a commit to branch version3
in repository https://gitbox.apache.org/repos/asf/empire-db.git
The following commit(s) were added to refs/heads/version3 by this push:
new bd625af EMPIREDB-368 DBUtils queryBeans functions
bd625af is described below
commit bd625af633a53fabaaa5aea8f9e02a6b194c5917
Author: Rainer Döbele <[email protected]>
AuthorDate: Tue Feb 1 01:02:37 2022 +0100
EMPIREDB-368 DBUtils queryBeans functions
---
.../org/apache/empire/samples/db/SampleApp.java | 21 +-
.../org/apache/empire/samples/db/SampleDB.java | 12 +
.../apache/empire/samples/db/beans/Department.java | 77 +++++++
.../apache/empire/samples/db/beans/Employee.java | 66 +++++-
.../apache/empire/samples/db/beans/Payment.java | 77 +++++++
.../main/java/org/apache/empire/data/Entity.java | 2 +
.../java/org/apache/empire/db/DBColumnExpr.java | 10 +
.../main/java/org/apache/empire/db/DBDatabase.java | 37 +++-
.../src/main/java/org/apache/empire/db/DBExpr.java | 37 +---
.../main/java/org/apache/empire/db/DBReader.java | 2 +-
.../java/org/apache/empire/db/DBRecordData.java | 2 +-
.../main/java/org/apache/empire/db/DBRowSet.java | 92 +++++++-
.../main/java/org/apache/empire/db/DBUtils.java | 245 +++++++++++++++++----
.../db/exceptions/UnknownBeanTypeException.java | 35 +++
.../main/java/org/apache/empire/db/list/Bean.java | 27 +++
.../apache/empire/db/list/DBBeanListFactory.java | 36 +++
.../empire/db/list/DBBeanListFactoryImpl.java | 154 +++++++++++++
17 files changed, 844 insertions(+), 88 deletions(-)
diff --git
a/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/SampleApp.java
b/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/SampleApp.java
index d9e9516..4ae69db 100644
---
a/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/SampleApp.java
+++
b/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/SampleApp.java
@@ -26,7 +26,6 @@ import java.time.LocalDate;
import java.util.List;
import org.apache.empire.commons.StringUtils;
-import org.apache.empire.data.bean.BeanResult;
import org.apache.empire.data.list.DataListEntry;
import org.apache.empire.db.DBColumnExpr;
import org.apache.empire.db.DBCommand;
@@ -45,8 +44,10 @@ import org.apache.empire.dbms.h2.DBMSHandlerH2;
import org.apache.empire.dbms.hsql.DBMSHandlerHSql;
import org.apache.empire.dbms.postgresql.DBMSHandlerPostgreSQL;
import org.apache.empire.samples.db.SampleDB.Gender;
+import org.apache.empire.samples.db.beans.Department;
import org.apache.empire.samples.db.beans.Employee;
import org.apache.empire.samples.db.beans.EmployeeQuery;
+import org.apache.empire.samples.db.beans.Payment;
import org.apache.empire.xml.XMLWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -712,6 +713,23 @@ public class SampleApp
private static void queryBeans()
{
SampleDB.Employees EMP = db.EMPLOYEES;
+
+ DBCommand cmd = db.createCommand();
+ cmd.where(EMP.GENDER.is(Gender.M));
+ cmd.orderBy(EMP.LASTNAME.desc());
+ List<Employee> list = context.getUtils().queryBeanList(cmd,
Employee.class, null);
+
+ for (Employee emp : list)
+ {
+
+ System.out.println(emp.toString());
+ }
+
+ // load department
+ Department department =
context.getUtils().queryBean(Department.class, db.DEPARTMENTS.NAME.is("Sales"));
+ Payment first =
department.getEmployees().get(0).getPayments().get(0);
+ log.info("First payment amount is {}", first.getAmount());
+ /*
// Query all males
BeanResult<Employee> result = new
BeanResult<Employee>(Employee.class, EMP);
result.getCommand().where(EMP.GENDER.is(Gender.M));
@@ -724,6 +742,7 @@ public class SampleApp
result.fetch(context);
log.info("Number of female employees is: "+result.size());
+ */
}
private static void queryDataList()
diff --git
a/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/SampleDB.java
b/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/SampleDB.java
index 0d8ec5e..b0fe93b 100644
---
a/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/SampleDB.java
+++
b/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/SampleDB.java
@@ -23,6 +23,9 @@ import org.apache.empire.db.DBColumn;
import org.apache.empire.db.DBDatabase;
import org.apache.empire.db.DBTable;
import org.apache.empire.db.DBTableColumn;
+import org.apache.empire.samples.db.beans.Department;
+import org.apache.empire.samples.db.beans.Employee;
+import org.apache.empire.samples.db.beans.Payment;
/**
* <PRE>
@@ -87,6 +90,9 @@ public class SampleDB extends DBDatabase
// setPrimaryKey(DEPARTMENT_ID);
// Set other Indexes
addIndex("DEPARTMENT_NAME_IDX", true, new DBColumn[] { NAME });
+
+ // Set beanType (optional)
+ setBeanType(Department.class);
}
}
@@ -126,6 +132,9 @@ public class SampleDB extends DBDatabase
// setPrimaryKey(EMPLOYEE_ID);
// Set other Indexes
addIndex("EMPLOYEE_NAME_IDX", true, new DBColumn[] { FIRSTNAME,
LASTNAME, DATE_OF_BIRTH });
+
+ // Set beanType (optional)
+ setBeanType(Employee.class);
}
}
@@ -152,6 +161,9 @@ public class SampleDB extends DBDatabase
// Primary Key (automatically set due to AUTOINC column)
setPrimaryKey(EMPLOYEE_ID, YEAR, MONTH);
// Set other Indexes
+
+ // Set beanType (optional)
+ setBeanType(Payment.class);
}
}
diff --git
a/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/beans/Department.java
b/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/beans/Department.java
new file mode 100644
index 0000000..c23e3e5
--- /dev/null
+++
b/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/beans/Department.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.empire.samples.db.beans;
+
+import java.util.List;
+
+import org.apache.empire.db.DBCommand;
+import org.apache.empire.db.DBContext;
+import org.apache.empire.db.DBRecordData;
+import org.apache.empire.db.list.Bean;
+import org.apache.empire.samples.db.SampleDB;
+
+public class Department implements Bean
+{
+ private long id; // "ID"
+ private String name; // "FIRSTNAME"
+ private String head; // "FIRSTNAME"
+
+ private List<Employee> employees;
+
+ public long getId()
+ {
+ return id;
+ }
+ public void setId(long id)
+ {
+ this.id = id;
+ }
+ public String getName()
+ {
+ return name;
+ }
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+ public String getHead()
+ {
+ return head;
+ }
+ public void setHead(String head)
+ {
+ this.head = head;
+ }
+
+ public List<Employee> getEmployees()
+ {
+ return employees;
+ }
+
+ @Override
+ public void onBeanLoaded(DBContext context, DBRecordData dataRow, int
rownum, Object parent)
+ {
+ SampleDB db = (SampleDB)dataRow.getDatabase();
+ DBCommand cmd = db.createCommand();
+ cmd.where(db.EMPLOYEES.DEPARTMENT_ID.is(this.id));
+ cmd.orderBy(db.EMPLOYEES.FIRSTNAME, db.EMPLOYEES.LASTNAME);
+ employees = context.getUtils().queryBeanList(cmd, Employee.class,
this);
+ }
+
+}
diff --git
a/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/beans/Employee.java
b/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/beans/Employee.java
index 9e569ad..57ea9ce 100644
---
a/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/beans/Employee.java
+++
b/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/beans/Employee.java
@@ -19,18 +19,27 @@
package org.apache.empire.samples.db.beans;
import java.math.BigDecimal;
+import java.sql.Timestamp;
import java.util.Date;
+import java.util.List;
import java.util.Locale;
import org.apache.empire.commons.DateUtils;
+import org.apache.empire.db.DBCommand;
+import org.apache.empire.db.DBContext;
+import org.apache.empire.db.DBRecord;
+import org.apache.empire.db.DBRecordData;
+import org.apache.empire.db.list.Bean;
+import org.apache.empire.samples.db.SampleDB;
/**
* This is an employee entity bean
* @author doebele
*
*/
-public class Employee
+public class Employee implements Bean
{
+ private int rownum; // rownum
private long id; // "ID"
private String firstname; // "FIRSTNAME"
private String lastname; // "LASTNAME"
@@ -41,8 +50,12 @@ public class Employee
private BigDecimal salary; // "SALARY"
private boolean retired; // "RETIRED"
+ private Department department;
+ private List<Payment> payments;
+
/**
* Creates a new Employee entity bean
+ * @param rownum
* @param id
* @param firstname
* @param lastname
@@ -53,9 +66,25 @@ public class Employee
* @param salary
* @param retired
*/
+ public Employee(int rownum, int id, String firstname, String lastname,
Date dateOfBirth, int departmentId, String gender, String phoneNumber,
+ BigDecimal salary, boolean retired, Timestamp timestamp)
+ {
+ this.rownum = rownum;
+ this.id = id;
+ this.firstname = firstname;
+ this.lastname = lastname;
+ this.dateOfBirth = dateOfBirth;
+ this.departmentId = departmentId;
+ this.gender = gender;
+ this.phoneNumber = phoneNumber;
+ this.salary = salary;
+ this.retired = retired;
+ }
+
public Employee(int id, String firstname, String lastname, Date
dateOfBirth, int departmentId, String gender, String phoneNumber,
- BigDecimal salary, boolean retired)
+ BigDecimal salary, boolean retired, Timestamp timestamp)
{
+ this.rownum = -1;
this.id = id;
this.firstname = firstname;
this.lastname = lastname;
@@ -67,6 +96,11 @@ public class Employee
this.retired = retired;
}
+ public Employee(int rownum)
+ {
+ this.rownum = rownum;
+ }
+
public Employee()
{
// Standard constructor
@@ -162,10 +196,22 @@ public class Employee
this.retired = retired;
}
+ public Department getDepartment()
+ {
+ return department;
+ }
+
+ public List<Payment> getPayments()
+ {
+ return payments;
+ }
+
@Override
public String toString()
{
StringBuffer buf = new StringBuffer();
+ buf.append(rownum);
+ buf.append("\t");
buf.append(id);
buf.append("\t");
buf.append(firstname);
@@ -182,5 +228,21 @@ public class Employee
return buf.toString();
}
+ @Override
+ public void onBeanLoaded(DBContext context, DBRecordData dataRow, int
rownum, Object parent)
+ {
+ if (parent instanceof Department)
+ department = ((Department)parent);
+ else
+ department = context.getUtils().queryBean(Department.class,
DBRecord.key(this.departmentId));
+
+ SampleDB db = (SampleDB)dataRow.getDatabase();
+ DBCommand cmd = db.createCommand();
+ cmd.where(db.PAYMENTS.EMPLOYEE_ID.is(this.id));
+ cmd.orderBy(db.PAYMENTS.YEAR.desc());
+ cmd.orderBy(db.PAYMENTS.MONTH.desc());
+ payments = context.getUtils().queryBeanList(cmd, Payment.class, this);
+ }
+
}
diff --git
a/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/beans/Payment.java
b/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/beans/Payment.java
new file mode 100644
index 0000000..2772a5c
--- /dev/null
+++
b/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/beans/Payment.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.empire.samples.db.beans;
+
+import java.math.BigDecimal;
+
+import org.apache.empire.db.DBContext;
+import org.apache.empire.db.DBRecordData;
+import org.apache.empire.db.list.Bean;
+
+public class Payment implements Bean
+{
+ private long employeeId;
+ private BigDecimal year;
+ private BigDecimal month;
+ private BigDecimal amount;
+
+ private Employee employee;
+
+ public Payment(long employeeId, BigDecimal year, BigDecimal month,
BigDecimal amount)
+ {
+ super();
+ this.employeeId = employeeId;
+ this.year = year;
+ this.month = month;
+ this.amount = amount;
+ }
+
+ public long getEmployeeId()
+ {
+ return employeeId;
+ }
+
+ public BigDecimal getYear()
+ {
+ return year;
+ }
+
+ public BigDecimal getMonth()
+ {
+ return month;
+ }
+
+ public BigDecimal getAmount()
+ {
+ return amount;
+ }
+
+ public Employee getEmployee()
+ {
+ return employee;
+ }
+
+ @Override
+ public void onBeanLoaded(DBContext context, DBRecordData dataRow, int
rownum, Object parent)
+ {
+ if (parent instanceof Employee)
+ this.employee = (Employee)parent;
+ }
+
+}
diff --git a/empire-db/src/main/java/org/apache/empire/data/Entity.java
b/empire-db/src/main/java/org/apache/empire/data/Entity.java
index 7344fbf..ea5d865 100644
--- a/empire-db/src/main/java/org/apache/empire/data/Entity.java
+++ b/empire-db/src/main/java/org/apache/empire/data/Entity.java
@@ -9,4 +9,6 @@ public interface Entity
List<? extends Column> getColumns();
Column[] getKeyColumns();
+
+ Class<?> getBeanType();
}
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBColumnExpr.java
b/empire-db/src/main/java/org/apache/empire/db/DBColumnExpr.java
index 5cd965a..903f771 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBColumnExpr.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBColumnExpr.java
@@ -1332,5 +1332,15 @@ public abstract class DBColumnExpr extends DBExpr
{
return new DBConcatFuncExpr(this, separator, concatExprs);
}
+
+ /**
+ * returns a corresponding Java type for this expression
+ * @param expr
+ * @return
+ */
+ public Class<?> getJavaType()
+ {
+ return this.getDatabase().getColumnJavaType(this);
+ }
}
\ No newline at end of file
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBDatabase.java
b/empire-db/src/main/java/org/apache/empire/db/DBDatabase.java
index 98bd1ba..335102d 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBDatabase.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBDatabase.java
@@ -21,6 +21,7 @@ package org.apache.empire.db;
import java.lang.ref.WeakReference;
import java.math.BigDecimal;
import java.math.RoundingMode;
+import java.sql.Timestamp;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.LocalDateTime;
@@ -514,7 +515,41 @@ public abstract class DBDatabase extends DBObject
buf.append(linkName);
}
}
-
+
+ /**
+ * Returns the java class type for a given dataType
+ * @param type the data type
+ * @return return the java class used for storing values of this dataType
+ */
+ public Class<?> getColumnJavaType(DBColumnExpr expr)
+ {
+ switch(expr.getDataType())
+ {
+ case AUTOINC:
+ case INTEGER:
+ return Long.class;
+ case VARCHAR:
+ case CLOB:
+ case CHAR:
+ return String.class;
+ case DATE:
+ case DATETIME:
+ return Date.class;
+ case TIMESTAMP:
+ return Timestamp.class;
+ case FLOAT:
+ return Double.class;
+ case DECIMAL:
+ return java.math.BigDecimal.class;
+ case BOOL:
+ return Boolean.class;
+ case BLOB:
+ return byte[].class;
+ default:
+ return Object.class;
+ }
+ }
+
/**
* Creates and returns a value object for the database systems
* current date and time.
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBExpr.java
b/empire-db/src/main/java/org/apache/empire/db/DBExpr.java
index 09c272b..89d7a57 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBExpr.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBExpr.java
@@ -19,7 +19,6 @@
package org.apache.empire.db;
import java.util.Collection;
-import java.util.Date;
import java.util.Set;
import org.apache.empire.commons.ObjectUtils;
@@ -125,39 +124,5 @@ public abstract class DBExpr extends DBObject
// Get Value Expression from dmbs
return dbms.getValueString(value, dataType);
}
- }
-
- /**
- * Returns the java class type for a given dataType
- * @param type the data type
- * @return return the java class used for storing values of this dataType
- */
- public static final Class<?> getValueClass(DataType type)
- {
- switch(type)
- {
- case AUTOINC:
- case INTEGER:
- return Long.class;
- case VARCHAR:
- case CLOB:
- case CHAR:
- return String.class;
- case DATE:
- case DATETIME:
- case TIMESTAMP:
- return Date.class;
- case FLOAT:
- return Double.class;
- case DECIMAL:
- return java.math.BigDecimal.class;
- case BOOL:
- return Boolean.class;
- case BLOB:
- return byte[].class;
- default:
- return Object.class;
- }
- }
-
+ }
}
\ No newline at end of file
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBReader.java
b/empire-db/src/main/java/org/apache/empire/db/DBReader.java
index 5ebd1c8..0eba5f7 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBReader.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBReader.java
@@ -986,7 +986,7 @@ public class DBReader extends DBRecordData implements
DBContextAware, Closeable
// Check whether we can use a constructor
Class<?>[] paramTypes = new Class[getFieldCount()];
for (int i = 0; i < columns.length; i++)
- paramTypes[i] = DBExpr.getValueClass(columns[i].getDataType());
+ paramTypes[i] = columns[i].getJavaType();
// Find Constructor
Constructor<?> ctor =
ClassUtils.findMatchingAccessibleConstructor(beanClass, paramTypes);
return ctor;
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBRecordData.java
b/empire-db/src/main/java/org/apache/empire/db/DBRecordData.java
index 7ee7915..55aeaec 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBRecordData.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBRecordData.java
@@ -520,7 +520,7 @@ public abstract class DBRecordData extends DBObject
// Add all Columns
int count = 0;
for (int i = 0; i < getFieldCount(); i++)
- { // Check Property
+ { // Check Property
ColumnExpr column = getColumnExpr(i);
if (ignoreList != null && ignoreList.contains(column))
continue; // ignore this property
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBRowSet.java
b/empire-db/src/main/java/org/apache/empire/db/DBRowSet.java
index 4db4c88..cc562d9 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBRowSet.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBRowSet.java
@@ -46,6 +46,8 @@ import
org.apache.empire.db.exceptions.RecordUpdateFailedException;
import org.apache.empire.db.exceptions.RecordUpdateInvalidException;
import org.apache.empire.db.expr.column.DBCountExpr;
import org.apache.empire.db.expr.compare.DBCompareExpr;
+import org.apache.empire.db.list.DBBeanListFactory;
+import org.apache.empire.db.list.DBBeanListFactoryImpl;
import org.apache.empire.dbms.DBMSFeature;
import org.apache.empire.dbms.DBMSHandler;
import org.apache.empire.dbms.DBSqlPhrase;
@@ -95,18 +97,52 @@ public abstract class DBRowSet extends DBExpr implements
Entity
fields[index]=value;
}
}
-
+
// Logger
- protected static final Logger log =
LoggerFactory.getLogger(DBRowSet.class);
+ protected static final Logger log =
LoggerFactory.getLogger(DBRowSet.class);
+
+ private static final Map<Class<?>, DBRowSet> beanTypeMap = new
HashMap<Class<?>, DBRowSet>(); /* ConcurrentHashMap ? */
+
+ /**
+ * Returns the DBRowSet instance assigned to a particular Java bean type
+ * @param beanType the Java bean type
+ * @return return the DBRowSet assigned to this type
+ */
+ public static synchronized DBRowSet getRowsetforType(Class<?> beanType)
+ {
+ return beanTypeMap.get(beanType);
+ }
+
+ /**
+ * sets the DBRowSet instance assigned to a particular Java bean type
+ * @param beanType the Java bean type
+ */
+ public static synchronized void setRowsetForType(Class<?> beanType,
DBRowSet rowset)
+ {
+ if (rowset!=null)
+ { // Check previous
+ DBRowSet prev = beanTypeMap.get(beanType);
+ if (prev!=null && prev!=rowset)
+ log.warn("The Java bean type '{}' has already been assigned to
a different DBRowSet {}. Assiging now to {}", beanType.getName(),
prev.getName(), rowset.getName());
+ // Assign now
+ beanTypeMap.put(beanType, rowset);
+ }
+ else
+ beanTypeMap.remove(beanType);
+ }
- // Members
- protected final DBDatabase db; /* transient */
- protected String comment = null;
- protected DBColumn timestampColumn = null;
- protected Map<DBColumn, DBColumn> columnReferences = null;
+ // Members
+ protected final DBDatabase db; /* transient ? */
+ protected String comment = null;
+ protected DBColumn timestampColumn = null;
+ protected Map<DBColumn, DBColumn> columnReferences = null;
+
+ protected Class<?> beanType = null;
+ protected DBBeanListFactory<?> beanFactory = null;
+
// The column List
- protected List<DBColumn> columns = new
ArrayList<DBColumn>();
+ protected List<DBColumn> columns = new
ArrayList<DBColumn>();
/**
* Internally used for parameter checking
@@ -264,6 +300,46 @@ public abstract class DBRowSet extends DBExpr implements
Entity
String schema = db.getSchema();
return (schema!=null) ? schema+"."+name : name;
}
+
+ /**
+ * returns the bean type for this rowset
+ * @return the bean type
+ */
+ @Override
+ public Class<?> getBeanType()
+ {
+ return beanType;
+ }
+
+ /**
+ * returns the bean factory for this rowset
+ * @return the bean factory
+ */
+ public DBBeanListFactory<?> getBeanFactory()
+ {
+ return beanFactory;
+ }
+
+ /**
+ * sets the bean type for this rowset
+ * @param beanType
+ */
+ public void setBeanType(Class<?> beanType)
+ {
+ setBeanType(beanType, null);
+ }
+
+ /**
+ * sets the bean type for this rowset
+ * @param beanType
+ */
+ public <T> void setBeanType(Class<T> beanType, DBBeanListFactory<T>
factory)
+ {
+ this.beanType = beanType;
+ this.beanFactory = (beanFactory!=null ? beanFactory : new
DBBeanListFactoryImpl<T>(beanType, this.columns));
+ // set to global map
+ setRowsetForType(beanType, this);
+ }
/**
* @see org.apache.empire.db.DBExpr#addReferencedColumns(Set)
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBUtils.java
b/empire-db/src/main/java/org/apache/empire/db/DBUtils.java
index a73fe83..0fad0d8 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBUtils.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBUtils.java
@@ -20,6 +20,11 @@ import
org.apache.empire.db.exceptions.ConstraintViolationException;
import org.apache.empire.db.exceptions.QueryFailedException;
import org.apache.empire.db.exceptions.QueryNoResultException;
import org.apache.empire.db.exceptions.StatementFailedException;
+import org.apache.empire.db.exceptions.UnknownBeanTypeException;
+import org.apache.empire.db.expr.compare.DBCompareExpr;
+import org.apache.empire.db.list.Bean;
+import org.apache.empire.db.list.DBBeanListFactory;
+import org.apache.empire.db.list.DBBeanListFactoryImpl;
import org.apache.empire.db.list.DBRecordListFactory;
import org.apache.empire.db.list.DBRecordListFactoryImpl;
import org.apache.empire.dbms.DBMSFeature;
@@ -643,6 +648,17 @@ public class DBUtils implements DBContextAware
return querySingleRow(cmd.getSelect(), cmd.getParamValues());
}
+
+ /**
+ * Called to inform that the limit for DataList, Record and Bean queries
has exceeded the maximum value
+ */
+ protected void queryRowLimitExeeded()
+ {
+ log.warn("********************************************************");
+ log.warn("Query Result was limited to {} by MAX_QUERY_ROWS",
MAX_QUERY_ROWS);
+ log.warn("********************************************************");
+ }
+
/**
* Crates a default DataListFactory for a DataListEntry class
* The DataListEntry class must provide the following constructor
@@ -670,7 +686,7 @@ public class DBUtils implements DBContextAware
* @param sqlCmd the SQL-Command for the query
* @param factory the Factory to be used for each list item
* @param first the number of records to skip from the beginning of the
result
- * @param pageSize the maximum number of item to return
+ * @param pageSize the maximum number of items to add to the list or -1
(default) for all
* @return the list
*/
public <T extends DataListEntry> List<T> queryDataList(DBCommand cmd,
DataListFactory<T> factory, int first, int pageSize)
@@ -721,11 +737,8 @@ public class DBUtils implements DBContextAware
}
// check
if (rownum==MAX_QUERY_ROWS)
- {
-
log.warn("********************************************************");
- log.warn("Query Result was limited to {} by MAX_QUERY_ROWS",
rownum);
-
log.warn("********************************************************");
- }
+ queryRowLimitExeeded();
+ // done
return list;
}
finally
@@ -811,7 +824,7 @@ public class DBUtils implements DBContextAware
* @param sqlCmd the SQL-Command for the query
* @param listHead the HeadInfo to be used for each list item
* @param first the number of records to skip from the beginning of the
result
- * @param pageSize the maximum number of item to return
+ * @param pageSize the maximum number of items to add to the list or -1
(default) for all
* @return the list
*/
public <T extends DBRecord> List<T> queryRecordList(DBCommand cmd,
DBRecordListFactory<T> factory, int first, int pageSize)
@@ -865,11 +878,8 @@ public class DBUtils implements DBContextAware
}
// check
if (rownum==MAX_QUERY_ROWS)
- {
-
log.warn("********************************************************");
- log.warn("Query Result was limited to {} by MAX_QUERY_ROWS",
rownum);
-
log.warn("********************************************************");
- }
+ queryRowLimitExeeded();
+ // done
return list;
}
finally
@@ -894,19 +904,50 @@ public class DBUtils implements DBContextAware
return queryRecordList(cmd, factory, 0, -1);
}
- /**#
+ /**
+ * Crates a default DBBeanListFactory for Java bean class
+ * The DBRecord class must provide
+ * either a standard construtor with correspondig property set
fundtions
+ * or a constructor using the fields of the query
+ * @param beanType the beanType for which to create the list head
+ * @param constructorParams the columns to be used for the constructor
(optional)
+ * @return the bean factory
+ */
+ protected <T> DBBeanListFactory<T> createDefaultBeanListFactory(Class<T>
beanType, List<? extends DBColumnExpr> constructorParams)
+ {
+ return new DBBeanListFactoryImpl<T>(beanType, constructorParams);
+ }
+
+ /**
+ * Crates a default DBBeanListFactory for Java bean class
+ * @param beanType the beanType for which to create the list head
+ * @param constructorParams the columns to be used for the constructor
(optional)
+ * @return the bean factory
+ */
+ protected final <T> DBBeanListFactory<T>
createDefaultBeanListFactory(Class<T> beanType, DBColumnExpr[]
constructorParams)
+ {
+ List<DBColumnExpr> params = new
ArrayList<DBColumnExpr>(constructorParams.length);
+ for (int i=0; i<constructorParams.length; i++)
+ params.add(constructorParams[i]);
+ return createDefaultBeanListFactory(beanType, params);
+ }
+
+ /**
* Query a list of simple Java objects (beans)
* @param cmd the comman
* @param type
* @param first
- * @param pageSize
+ * @param pageSize the maximum number of items to add to the list or -1
(default) for all
* @return
*/
- public <T> List<T> queryBeanList(DBCommand cmd, Class<T> type, int first,
int pageSize)
+ public <T> List<T> queryBeanList(DBCommand cmd, DBBeanListFactory<T>
factory, Object parent, int first, int pageSize)
{
+ List<T> list = null;
DBReader r = new DBReader(context);
try
- { // check pageSize
+ { // prepare
+ factory.prepareQuery(cmd, context);
+ // check pageSize
if (pageSize==0)
{ log.warn("PageSize must not be 0. Setting to -1 for all
records!");
pageSize = -1;
@@ -929,51 +970,179 @@ public class DBUtils implements DBContextAware
{ // skip rows
r.skipRows(first);
}
- ArrayList<T> list = r.getBeanList(type, pageSize);
- // check sortable
- /*
- if (EnumerableListEntry.class.isAssignableFrom(type))
- {
- int rownum = 0;
- for (EnumerableListEntry sle : ((ArrayList<? extends
EnumerableListEntry>)list))
- {
- sle.setRownum(++rownum);
- }
+ // Create a list of data entries
+ int maxCount = (pageSize>=0) ? pageSize : MAX_QUERY_ROWS;
+ list = factory.newList((pageSize>=0) ? pageSize :
DEFAULT_LIST_CAPACITY);
+ // add data
+ int rownum = 0;
+ while (r.moveNext() && maxCount != 0)
+ { // Create bean an init
+ T item = factory.newItem(++rownum, r);
+ if (item==null)
+ continue;
+ // post processing
+ if (item instanceof Bean)
+ ((Bean)item).onBeanLoaded(context, r, rownum, parent);
+ // add entry
+ list.add(item);
+ // Decrease count
+ if (maxCount > 0)
+ maxCount--;
}
- */
+ // check
+ if (rownum==MAX_QUERY_ROWS)
+ queryRowLimitExeeded();
+ // done
return list;
}
finally
{
r.close();
+ // complete
+ if (list!=null)
+ factory.completeQuery(list);
}
}
- public <T> List<T> queryBeanList(DBCommand cmd, Class<T> type)
+ /**
+ * Queries a single Java Bean for a given command
+ * If the command has no select expressions then the beanType must be
assigned to a DBRowSet via DBRowSet.setBeanType()
+ * @param cmd the query command
+ * @param beanType the beanType
+ * @param first first item of query (default is 0)
+ * @param pageSize the maximum number of items to add to the list or -1
(default) for all
+ * @return the list of java beans
+ */
+ @SuppressWarnings("unchecked")
+ public <T> List<T> queryBeanList(DBCommand cmd, Class<T> beanType, Object
parent, int first, int pageSize)
+ {
+ DBBeanListFactory<T> factory;
+ if (cmd.hasSelectExpr()==false)
+ {
+ DBRowSet rowset = DBRowSet.getRowsetforType(beanType);
+ if (rowset==null)
+ throw new InvalidArgumentException("cmd", cmd);
+ // found, use factory of rowset
+ factory = (DBBeanListFactory<T>)rowset.getBeanFactory();
+ }
+ else
+ { // use default rowset
+ factory = createDefaultBeanListFactory(beanType,
cmd.getSelectExprList());
+ }
+ return queryBeanList(cmd, factory, parent, first, pageSize);
+ }
+
+ public final <T> List<T> queryBeanList(DBCommand cmd, Class<T> beanType,
List<? extends DBColumnExpr> constructorParams, Object parent)
{
- return queryBeanList(cmd, type, 0, -1);
+ return queryBeanList(cmd, createDefaultBeanListFactory(beanType,
constructorParams), parent, 0, -1);
}
+ public final <T> List<T> queryBeanList(DBCommand cmd, Class<T> beanType,
Object parent)
+ {
+ return queryBeanList(cmd, beanType, parent, 0, -1);
+ }
+
/**
- * Query a single bean's properties
- * @param cmd the bean query command
- * @param bean the bean for which to set the properties
- public int queryBeanProperties(DBCommand cmd, Object bean)
+ * queries a single Java Bean for a given command
+ * @param cmd the query command
+ * @param factory the factory to create the bean instance
+ * @return the bean instance
+ */
+ public <T> T queryBean(DBCommand cmd, DBBeanListFactory<T> factory)
{
+ List<T> list = null;
DBReader r = new DBReader(context);
try
- { // Runquery
+ { // prepare
+ factory.prepareQuery(cmd, context);
+ // Runquery
r.getRecordData(cmd);
- int count = r.setBeanProperties(bean);
- if (count<= 0)
- log.warn("No matching bean properties found!");
- return count;
+ // add data
+ T item = factory.newItem(-1, r);
+ // post processing
+ if (item instanceof Bean)
+ ((Bean)item).onBeanLoaded(context, r, -1, null);
+ // done
+ return item;
}
finally
{
r.close();
+ // complete
+ if (list!=null)
+ factory.completeQuery(list);
+ }
+ }
+
+ /**
+ * Queries a single Java Bean for a given command
+ * If the command has no select expressions then the beanType must be
assigned to a DBRowSet via DBRowSet.setBeanType()
+ * @param cmd the query command
+ * @param beanType the bean type
+ * @return the bean instance
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T queryBean(DBCommand cmd, Class<T> beanType)
+ {
+ DBBeanListFactory<T> factory;
+ if (cmd.hasSelectExpr()==false)
+ {
+ DBRowSet rowset = DBRowSet.getRowsetforType(beanType);
+ if (rowset==null)
+ throw new UnknownBeanTypeException(beanType);
+ // found, use factory of rowset
+ factory = (DBBeanListFactory<T>)rowset.getBeanFactory();
+ }
+ else
+ { // use default rowset
+ factory = createDefaultBeanListFactory(beanType,
cmd.getSelectExprList());
}
+ return queryBean(cmd, factory);
+ }
+
+ public final <T> T queryBean(DBCommand cmd, Class<T> beanType, List<?
extends DBColumnExpr> constructorParams, Object parent)
+ {
+ return queryBean(cmd, createDefaultBeanListFactory(beanType,
constructorParams));
}
+
+ /**
+ * Queries a single bean based on a set of where constraints
+ * @param beanType the beanType
+ * @param whereConstraints
+ * @return
*/
+ public final <T> T queryBean(Class<T> beanType, DBCompareExpr
whereConstraints)
+ {
+ if (whereConstraints==null)
+ throw new InvalidArgumentException("whereConstraints",
whereConstraints);
+ // find
+ DBDatabase db = whereConstraints.getDatabase();
+ DBCommand cmd = db.createCommand();
+ cmd.where(whereConstraints);
+ return queryBean(cmd, beanType);
+ }
+
+ /**
+ * Queries a single bean based on a set of where constraints
+ * @param beanType the beanType
+ * @param whereConstraints
+ * @return
+ */
+ public final <T> T queryBean(Class<T> beanType, Object[] key)
+ {
+ if (key==null)
+ throw new InvalidArgumentException("key", key);
+ // find rowset
+ DBRowSet rowset = DBRowSet.getRowsetforType(beanType);
+ if (rowset==null)
+ throw new UnknownBeanTypeException(beanType);
+ // set key constraints
+ DBCommand cmd = rowset.getDatabase().createCommand();
+ rowset.setKeyConstraints(cmd, key);
+ // use factory of rowset
+ @SuppressWarnings("unchecked")
+ DBBeanListFactory<T> factory =
(DBBeanListFactory<T>)rowset.getBeanFactory();
+ return queryBean(cmd, factory);
+ }
}
diff --git
a/empire-db/src/main/java/org/apache/empire/db/exceptions/UnknownBeanTypeException.java
b/empire-db/src/main/java/org/apache/empire/db/exceptions/UnknownBeanTypeException.java
new file mode 100644
index 0000000..767f7ce
--- /dev/null
+++
b/empire-db/src/main/java/org/apache/empire/db/exceptions/UnknownBeanTypeException.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.empire.db.exceptions;
+
+import org.apache.empire.commons.ErrorType;
+import org.apache.empire.exceptions.EmpireException;
+
+public class UnknownBeanTypeException extends EmpireException
+{
+ private static final long serialVersionUID = 1L;
+
+ public static final ErrorType errorType = new
ErrorType("error.db.unknownBeanType", "Unknown bean type. The type '{0}' has
not been mapped to a table or view.");
+
+ public UnknownBeanTypeException(Class<?> beanType)
+ {
+ super(errorType, new String[] { beanType.getName() });
+ }
+
+}
diff --git a/empire-db/src/main/java/org/apache/empire/db/list/Bean.java
b/empire-db/src/main/java/org/apache/empire/db/list/Bean.java
new file mode 100644
index 0000000..8d87972
--- /dev/null
+++ b/empire-db/src/main/java/org/apache/empire/db/list/Bean.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.empire.db.list;
+
+import org.apache.empire.db.DBContext;
+import org.apache.empire.db.DBRecordData;
+
+public interface Bean
+{
+ void onBeanLoaded(DBContext context, DBRecordData dataRow, int rownum,
Object parent);
+}
diff --git
a/empire-db/src/main/java/org/apache/empire/db/list/DBBeanListFactory.java
b/empire-db/src/main/java/org/apache/empire/db/list/DBBeanListFactory.java
new file mode 100644
index 0000000..f46620a
--- /dev/null
+++ b/empire-db/src/main/java/org/apache/empire/db/list/DBBeanListFactory.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.empire.db.list;
+
+import java.util.List;
+
+import org.apache.empire.db.DBCommand;
+import org.apache.empire.db.DBContext;
+import org.apache.empire.db.DBRecordData;
+
+public interface DBBeanListFactory<T extends Object>
+{
+ void prepareQuery(DBCommand cmd, DBContext context);
+
+ List<T> newList(int capacity);
+
+ T newItem(int rownum, DBRecordData dataRow);
+
+ void completeQuery(List<T> list);
+}
diff --git
a/empire-db/src/main/java/org/apache/empire/db/list/DBBeanListFactoryImpl.java
b/empire-db/src/main/java/org/apache/empire/db/list/DBBeanListFactoryImpl.java
new file mode 100644
index 0000000..05f20ab
--- /dev/null
+++
b/empire-db/src/main/java/org/apache/empire/db/list/DBBeanListFactoryImpl.java
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.empire.db.list;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.empire.commons.ClassUtils;
+import org.apache.empire.db.DBColumnExpr;
+import org.apache.empire.db.DBCommand;
+import org.apache.empire.db.DBContext;
+import org.apache.empire.db.DBRecordData;
+import org.apache.empire.exceptions.InternalException;
+import org.apache.empire.exceptions.InvalidArgumentException;
+
+/**
+ * DBRecordListFactoryImpl
+ * Implements the DBRecordListFactory interface
+ * @author rainer
+ */
+public class DBBeanListFactoryImpl<T> implements DBBeanListFactory<T>
+{
+ /**
+ * Finds a suitable constructor for the beanClass
+ * @param beanType the bean class to instantiate
+ * @param params the constructor params
+ * @return the constructor
+ */
+ @SuppressWarnings("unchecked")
+ protected static <T> Constructor<T> findBeanConstructor(Class<T> beanType,
List<? extends DBColumnExpr> params)
+ {
+ // find a suitable constructor
+ Constructor<?> ctor = null;
+ if (params!=null)
+ { // param type array
+ Class<?>[] paramTypes = new Class[params.size()];
+ for (int i=0; i<paramTypes.length; i++)
+ paramTypes[i] = params.get(i).getJavaType();
+ // find constructor
+ ctor = ClassUtils.findMatchingAccessibleConstructor(beanType,
paramTypes);
+ }
+ if (ctor==null)
+ { // find default constructor
+ ctor = ClassUtils.findMatchingAccessibleConstructor(beanType, new
Class<?>[] {});
+ }
+ return (Constructor<T>)ctor;
+ }
+
+ /*
+ * Members
+ */
+ protected final Constructor<T> constructor;
+ protected final List<? extends DBColumnExpr> constructorParams;
+
+ /**
+ * Constructs a DBRecordListFactoryImpl based on an DBRecord constructor
+ * @param constructor the DBRecord constructor
+ * @param context the database context
+ * @param rowset the rowset for the created records
+ */
+ public DBBeanListFactoryImpl(Constructor<T> constructor, List<? extends
DBColumnExpr> constructorParams)
+ {
+ this.constructor = constructor;
+ this.constructorParams = constructorParams;
+ // Check constructor
+ if (constructor.getParameterCount()>0 && (constructorParams==null ||
constructor.getParameterCount()<constructorParams.size()))
+ throw new InvalidArgumentException("constructor", constructor);
+ }
+
+ /**
+ * Constructs a DBRecordListFactoryImpl based on an DBRecord class
+ * @param recordClass the record class to be created for this list
+ * @param context the database context
+ * @param rowset the rowset for the created records
+ */
+ public DBBeanListFactoryImpl(Class<T> beanType, List<? extends
DBColumnExpr> constructorParams)
+ {
+ this(findBeanConstructor(beanType, constructorParams),
constructorParams);
+ }
+
+ @Override
+ public void prepareQuery(DBCommand cmd, DBContext context)
+ {
+ if (constructorParams==null)
+ return;
+ // check if constructor params are selected and add if appropriate
+ for (DBColumnExpr expr : constructorParams)
+ {
+ if (cmd.hasSelectExpr(expr)==false)
+ cmd.select(expr);
+ }
+ }
+
+ @Override
+ public List<T> newList(int capacity)
+ {
+ return new ArrayList<T>(capacity);
+ }
+
+ @Override
+ public T newItem(int rownum, DBRecordData dataRow)
+ { try
+ { T bean;
+ if (constructorParams!=null && constructor.getParameterCount()>0)
+ { // Param constructor
+ Object[] params = new Object[constructor.getParameterCount()];
+ int i=0;
+ for (DBColumnExpr expr : constructorParams)
+ params[i++] = dataRow.getValue(expr);
+ // create item
+ bean = constructor.newInstance(params);
+ // set remaining properties
+ if (params.length < dataRow.getFieldCount())
+ dataRow.setBeanProperties(bean, constructorParams);
+ }
+ else
+ { // Standard constructor
+ bean = constructor.newInstance();
+ // set the properties
+ dataRow.setBeanProperties(bean);
+ }
+ return bean;
+ }
+ catch (InstantiationException | IllegalAccessException |
IllegalArgumentException | InvocationTargetException e)
+ {
+ throw new InternalException(e);
+ }
+ }
+
+ @Override
+ public void completeQuery(List<T> list)
+ {
+
+ }
+
+}