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 8163ec7 EMPIREDB-368 fix
8163ec7 is described below
commit 8163ec79fc865695d67345061d8cb2d974d7202c
Author: Rainer Döbele <[email protected]>
AuthorDate: Tue Feb 1 12:30:29 2022 +0100
EMPIREDB-368 fix
---
.../org/apache/empire/samples/db/SampleApp.java | 7 +-
.../apache/empire/samples/db/beans/Employee.java | 38 +++---
.../main/java/org/apache/empire/data/Record.java | 9 ++
.../org/apache/empire/data/bean/BeanResult.java | 130 ++++++++++++++-------
.../main/java/org/apache/empire/db/DBReader.java | 15 ++-
.../main/java/org/apache/empire/db/DBRowSet.java | 13 ++-
.../main/java/org/apache/empire/db/DBUtils.java | 33 +++---
7 files changed, 154 insertions(+), 91 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 469ba31..31a89b1 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
@@ -715,6 +715,7 @@ public class SampleApp
{
SampleDB.Employees EMP = db.EMPLOYEES;
+ /*
DBCommand cmd = db.createCommand();
cmd.where(EMP.GENDER.is(Gender.M));
cmd.orderBy(EMP.LASTNAME.desc());
@@ -729,9 +730,10 @@ public class SampleApp
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);
+ // Query all males
+ BeanResult<Employee> result = new
BeanResult<Employee>(Employee.class);
result.getCommand().where(EMP.GENDER.is(Gender.M));
result.fetch(context);
@@ -742,7 +744,6 @@ 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/beans/Employee.java
b/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/beans/Employee.java
index 2df7e43..bf44085 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
@@ -27,7 +27,6 @@ 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.list.Bean;
import org.apache.empire.samples.db.SampleDB;
@@ -38,7 +37,6 @@ import org.apache.empire.samples.db.SampleDB;
*/
public class Employee implements Bean<SampleDB>
{
- private int rownum; // rownum
private long id; // "ID"
private String firstname; // "FIRSTNAME"
private String lastname; // "LASTNAME"
@@ -52,9 +50,10 @@ public class Employee implements Bean<SampleDB>
private Department department;
private List<Payment> payments;
+ int rownum;
+
/**
- * Creates a new Employee entity bean
- * @param rownum
+ * Constructor using all fields from the table EMPLOYEES
* @param id
* @param firstname
* @param lastname
@@ -65,10 +64,9 @@ public class Employee implements Bean<SampleDB>
* @param salary
* @param retired
*/
- public Employee(int rownum, int id, String firstname, String lastname,
Date dateOfBirth, int departmentId, String gender, String phoneNumber,
+ public Employee(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;
@@ -80,26 +78,18 @@ public class Employee implements Bean<SampleDB>
this.retired = retired;
}
+ /**
+ * Constructor using fields but without timestamp
+ */
public Employee(int id, String firstname, String lastname, Date
dateOfBirth, int departmentId, String gender, String phoneNumber,
- BigDecimal salary, boolean retired, Timestamp timestamp)
- {
- this.rownum = -1;
- 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 rownum)
+ BigDecimal salary, boolean retired)
{
- this.rownum = rownum;
+ this(id, firstname, lastname, dateOfBirth, departmentId, gender,
phoneNumber, salary, retired, null);
}
+ /**
+ * Standard Constructor
+ */
public Employee()
{
// Standard constructor
@@ -230,10 +220,12 @@ public class Employee implements Bean<SampleDB>
@Override
public void onBeanLoaded(SampleDB db, DBContext context, int rownum,
Object parent)
{
+ this.rownum = rownum;
+
if (parent instanceof Department)
department = ((Department)parent);
// don't!
- else department = context.getUtils().queryBean(Department.class,
db.DEPARTMENTS, DBRecord.key(this.departmentId));
+ // else department = context.getUtils().queryBean(Department.class,
DBRecord.key(this.departmentId));
DBCommand cmd = db.createCommand();
cmd.where(db.PAYMENTS.EMPLOYEE_ID.is(this.id));
diff --git a/empire-db/src/main/java/org/apache/empire/data/Record.java
b/empire-db/src/main/java/org/apache/empire/data/Record.java
index 196cdf1..a976318 100644
--- a/empire-db/src/main/java/org/apache/empire/data/Record.java
+++ b/empire-db/src/main/java/org/apache/empire/data/Record.java
@@ -34,6 +34,15 @@ import org.apache.empire.commons.Options;
*/
public interface Record extends RecordData
{
+ /**
+ * varArgs to Array
+ * @param parts
+ * @return
+ */
+ public static Object[] key(Object... parts)
+ {
+ return parts;
+ }
/**
* returns true if the record is valid.
diff --git
a/empire-db/src/main/java/org/apache/empire/data/bean/BeanResult.java
b/empire-db/src/main/java/org/apache/empire/data/bean/BeanResult.java
index 519187a..0b3d429 100644
--- a/empire-db/src/main/java/org/apache/empire/data/bean/BeanResult.java
+++ b/empire-db/src/main/java/org/apache/empire/data/bean/BeanResult.java
@@ -26,10 +26,11 @@ import org.apache.empire.db.DBColumn;
import org.apache.empire.db.DBCommand;
import org.apache.empire.db.DBContext;
import org.apache.empire.db.DBDatabase;
+import org.apache.empire.db.DBObject;
import org.apache.empire.db.DBReader;
import org.apache.empire.db.DBRowSet;
+import org.apache.empire.db.exceptions.CommandWithoutSelectException;
import org.apache.empire.exceptions.BeanIncompatibleException;
-import org.apache.empire.exceptions.InvalidArgumentException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -50,80 +51,78 @@ public class BeanResult<T> extends ArrayList<T>
private static final Logger log =
LoggerFactory.getLogger(BeanResult.class);
private DBCommand cmd;
- private Class<T> clazz;
+ private Class<T> beanType;
/**
* Create a bean result from a command object.
* No checks will be performed here whether the command is compatible with
the supplied class.
- * @param clazz
+ * @param beanType
* @param cmd
*/
- public BeanResult(Class<T> clazz, DBCommand cmd)
+ public BeanResult(Class<T> beanType, DBCommand cmd)
{
- this.clazz = clazz;
+ DBObject.checkParamNull("beanType", beanType);
+ DBObject.checkParamNull("cmd", cmd);
+ this.beanType = beanType;
this.cmd = cmd;
- // Invalid Argument
- if (cmd==null || cmd.hasSelectExpr())
- throw new InvalidArgumentException("cmd", cmd);
}
/**
* Creates a bean result for a Table, View or Query from the supplied
columns.
* At least one column must match the given getters / setters on the
supplied class otherwise an BeanIncompatibleException will be thrown.
- * @param clazz the of T
+ * @param beanType the of T
* @param rowset the rowset
*/
- public BeanResult(Class<T> clazz, DBRowSet rowset)
+ public BeanResult(Class<T> beanType, DBRowSet rowset)
{
- this.clazz = clazz;
+ DBObject.checkParamNull("beanType", beanType);
+ DBObject.checkParamNull("rowset", rowset);
+ this.beanType = beanType;
// Create the command
DBDatabase db = rowset.getDatabase();
cmd = db.createCommand();
- // Select all accessible columns
- int count = 0;
- Method[] methods = clazz.getMethods();
- for (DBColumn col : rowset.getColumns())
- { // obtain the bean property Name
- String property = col.getBeanPropertyName();
- if (!isPropertyAcessible(methods, property, col.getDataType())) {
- // Property not found
- log.debug("Unable to access the property {} on {}. Column will
be ignored.", property, clazz.getName());
- continue;
- }
- // Select
- cmd.select(col);
- count++;
- }
- // Check
- if (count==0)
- throw new BeanIncompatibleException(clazz, rowset);
+ autoSelectColumns(rowset);
}
-
- protected boolean isPropertyAcessible(Method[] methods, String property,
DataType dataType)
+
+ /**
+ * Creates a bean result for a Table, View or Query from the supplied
columns.
+ * A rowset must be registered for this beanType @see
DBRowSet.getRowsetforType()
+ * At least one column must match the given getters / setters on the
supplied class otherwise an BeanIncompatibleException will be thrown.
+ * @param beanType the of T
+ */
+ public BeanResult(Class<T> beanType)
{
- property =
"et"+property.substring(0,1).toUpperCase()+property.substring(1);
- for (int i=0; i<methods.length; i++)
- { // Find a matching getter or setter method
- String name = methods[i].getName();
- if (name.endsWith(property))
- return true;
- }
- return false;
+ this(beanType, DBRowSet.getRowsetforType(beanType, true));
}
+ /**
+ * Returns the current command
+ * Used to add constraints, order, grouping etc.
+ * @return the command
+ */
public DBCommand getCommand()
{
return cmd;
}
+ /**
+ * Executes the query and fetches the result
+ * @param context
+ * @param maxItems the maximum number of items to query
+ * @return the number of items fetched by the query
+ */
public int fetch(DBContext context, int maxItems)
{
+ // Check command
+ if (!cmd.hasSelectExpr())
+ throw new CommandWithoutSelectException(cmd);
+ // OK, fetch now
clear();
DBReader reader = new DBReader(context);
try {
// Open and Read
reader.open(cmd);
- reader.getBeanList(this, clazz, maxItems);
+ reader.getBeanList(this, beanType, maxItems);
return size();
} finally {
@@ -131,9 +130,60 @@ public class BeanResult<T> extends ArrayList<T>
}
}
+ /**
+ * Executes the query and fetches the result
+ * @param context
+ * @return the number of items fetched by the query
+ */
public final int fetch(DBContext context)
{
return fetch(context, -1);
}
+ /**
+ * Selects all columns for a given rowset
+ * @param rowset
+ */
+ protected void autoSelectColumns(DBRowSet rowset)
+ {
+ // Select all accessible columns
+ int count = 0;
+ Method[] methods = beanType.getMethods();
+ for (DBColumn col : rowset.getColumns())
+ { // obtain the bean property Name
+ String property = col.getBeanPropertyName();
+ if (!isPropertyAcessible(methods, property, col.getDataType())) {
+ // Property not found
+ log.info("Unable to access the property {} on {}. Column will
be ignored.", property, beanType.getName());
+ continue;
+ }
+ // Select
+ cmd.select(col);
+ count++;
+ }
+ log.debug("{} columns have been selected for beanType {}", count,
beanType.getName());
+ // Check
+ if (count==0)
+ throw new BeanIncompatibleException(beanType, rowset);
+ }
+
+ /**
+ * Checks if the property is accessible i.e. has a getter method on the
beanType
+ * @param methods the beanType methods
+ * @param propety the property to check
+ * @param dataType the dataType
+ */
+ protected boolean isPropertyAcessible(Method[] methods, String property,
DataType dataType)
+ {
+ String prefix = (dataType.isBoolean() ? "is" : "et");
+ String getter =
prefix+property.substring(0,1).toUpperCase()+property.substring(1);
+ for (int i=0; i<methods.length; i++)
+ { // Find a matching getter or setter method
+ String name = methods[i].getName();
+ if (name.endsWith(getter))
+ return true;
+ }
+ return false;
+ }
+
}
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 4f6875e..7fa315f 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
@@ -39,6 +39,7 @@ import org.apache.empire.data.DataType;
import org.apache.empire.db.exceptions.EmpireSQLException;
import org.apache.empire.db.exceptions.QueryNoResultException;
import org.apache.empire.db.expr.join.DBJoinExpr;
+import org.apache.empire.db.list.Bean;
import org.apache.empire.exceptions.BeanInstantiationException;
import org.apache.empire.exceptions.InvalidArgumentException;
import org.apache.empire.exceptions.ObjectNotValidException;
@@ -686,20 +687,24 @@ public class DBReader extends DBRecordData implements
Closeable
// Create a list of beans
while (moveNext() && maxCount != 0)
- { // Create bean an init
+ { // Create bean an init
+ T bean;
if (ctor!=null)
{ // Use Constructor
for (int i = 0; i < getFieldCount(); i++)
args[i] = ObjectUtils.convert(ctorParamTypes[i],
getValue(i));
- T bean = (T)ctor.newInstance(args);
- c.add(bean);
+ bean = (T)ctor.newInstance(args);
}
else
{ // Use Property Setters
- T bean = t.newInstance();
+ bean = t.newInstance();
setBeanProperties(bean);
- c.add(bean);
}
+ // add
+ c.add(bean);
+ // post processing
+ if (bean instanceof Bean<?>)
+ ((Bean<?>)bean).onBeanLoaded(getDatabase(), context,
c.size(), null);
// Decrease count
if (maxCount > 0)
maxCount--;
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 cc562d9..fa54020 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
@@ -27,6 +27,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import org.apache.empire.commons.ObjectUtils;
import org.apache.empire.commons.StringUtils;
@@ -44,6 +45,7 @@ import org.apache.empire.db.exceptions.QueryNoResultException;
import org.apache.empire.db.exceptions.RecordNotFoundException;
import org.apache.empire.db.exceptions.RecordUpdateFailedException;
import org.apache.empire.db.exceptions.RecordUpdateInvalidException;
+import org.apache.empire.db.exceptions.UnknownBeanTypeException;
import org.apache.empire.db.expr.column.DBCountExpr;
import org.apache.empire.db.expr.compare.DBCompareExpr;
import org.apache.empire.db.list.DBBeanListFactory;
@@ -101,16 +103,19 @@ public abstract class DBRowSet extends DBExpr implements
Entity
// Logger
protected static final Logger log =
LoggerFactory.getLogger(DBRowSet.class);
- private static final Map<Class<?>, DBRowSet> beanTypeMap = new
HashMap<Class<?>, DBRowSet>(); /* ConcurrentHashMap ? */
+ private static final Map<Class<?>, DBRowSet> beanTypeMap = new
ConcurrentHashMap<Class<?>, DBRowSet>();
/**
* 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);
+ public static synchronized DBRowSet getRowsetforType(Class<?> beanType,
boolean checkExists)
+ {
+ DBRowSet rowset = beanTypeMap.get(beanType);
+ if (rowset==null && checkExists)
+ throw new UnknownBeanTypeException(beanType);
+ return rowset;
}
/**
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 709d1c5..7b39736 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
@@ -16,12 +16,11 @@ import org.apache.empire.data.list.DataListFactory;
import org.apache.empire.data.list.DataListFactoryImpl;
import org.apache.empire.data.list.DataListHead;
import org.apache.empire.db.context.DBContextAware;
-import org.apache.empire.db.exceptions.ConstraintViolationException;
import org.apache.empire.db.exceptions.CommandWithoutSelectException;
+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;
@@ -727,11 +726,12 @@ public class DBUtils implements DBContextAware
int rownum = 0;
while (r.moveNext() && maxCount != 0)
{ // Create bean an init
- T entry = factory.newEntry(++rownum, r);
+ T entry = factory.newEntry(rownum, r);
if (entry==null)
continue;
// add entry
list.add(entry);
+ rownum++;
// Decrease count
if (maxCount > 0)
maxCount--;
@@ -865,12 +865,15 @@ public class DBUtils implements DBContextAware
int rownum = 0;
while (r.moveNext() && maxCount != 0)
{ // Create bean an init
- T entry = factory.newRecord(++rownum, r);
+ T entry = factory.newRecord(rownum, r);
if (entry==null)
continue;
- // add entry
+ // check
if (entry.isValid())
+ { // add entry
list.add(entry);
+ rownum++;
+ }
else
log.warn("Record {} is not valid thus it will not be added
to the RecordListQuery.", rownum);
// Decrease count
@@ -979,14 +982,16 @@ public class DBUtils implements DBContextAware
int rownum = 0;
while (r.moveNext() && maxCount != 0)
{ // Create bean an init
- T item = factory.newItem(++rownum, r);
+ T item = factory.newItem(rownum, r);
if (item==null)
continue;
+ // add entry
+ list.add(item);
// post processing
if (item instanceof Bean<?>)
((Bean<?>)item).onBeanLoaded(r.getDatabase(), context,
rownum, parent);
- // add entry
- list.add(item);
+ // next
+ rownum++;
// Decrease count
if (maxCount > 0)
maxCount--;
@@ -1055,7 +1060,7 @@ public class DBUtils implements DBContextAware
*/
public <T> List<T> queryBeanList(DBCommand cmd, Class<T> beanType, Object
parent)
{
- DBRowSet rowset = DBRowSet.getRowsetforType(beanType);
+ DBRowSet rowset = DBRowSet.getRowsetforType(beanType, false);
if (rowset!=null)
return queryBeanList(cmd, getRowsetBeanListFactory(beanType,
rowset), parent);
else
@@ -1115,7 +1120,7 @@ public class DBUtils implements DBContextAware
*/
public <T> T queryBean(DBCommand cmd, Class<T> beanType)
{
- DBRowSet rowset = DBRowSet.getRowsetforType(beanType);
+ DBRowSet rowset = DBRowSet.getRowsetforType(beanType, false);
if (rowset!=null)
return queryBean(cmd, getRowsetBeanListFactory(beanType, rowset));
else
@@ -1149,9 +1154,7 @@ public class DBUtils implements DBContextAware
*/
public final <T> T queryBean(Class<T> beanType, DBCompareExpr
whereConstraints)
{
- DBRowSet rowset = DBRowSet.getRowsetforType(beanType);
- if (rowset==null)
- throw new UnknownBeanTypeException(beanType);
+ DBRowSet rowset = DBRowSet.getRowsetforType(beanType, true);
return queryBean(beanType, rowset, whereConstraints);
}
@@ -1181,9 +1184,7 @@ public class DBUtils implements DBContextAware
*/
public final <T> T queryBean(Class<T> beanType, Object[] key)
{
- DBRowSet rowset = DBRowSet.getRowsetforType(beanType);
- if (rowset==null)
- throw new UnknownBeanTypeException(beanType);
+ DBRowSet rowset = DBRowSet.getRowsetforType(beanType, true);
return queryBean(beanType, rowset, key);
}