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 d11c07f EMPIREDB-368 new DBBeanListFactory logic
d11c07f is described below
commit d11c07fb7632f5730d735d9a085ac6415976a2a8
Author: Rainer Döbele <[email protected]>
AuthorDate: Thu Feb 3 21:46:32 2022 +0100
EMPIREDB-368 new DBBeanListFactory logic
---
.../org/apache/empire/samples/db/SampleApp.java | 6 +-
.../apache/empire/samples/db/beans/Employee.java | 31 ++++-
.../org/apache/empire/commons/ObjectUtils.java | 26 +++-
.../main/java/org/apache/empire/db/DBRowSet.java | 6 +-
.../main/java/org/apache/empire/db/DBUtils.java | 56 +--------
.../empire/db/list/DBBeanListFactoryImpl.java | 139 ++++++++++++++++-----
6 files changed, 172 insertions(+), 92 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 31a89b1..522ea3c 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;
@@ -715,14 +714,12 @@ public class SampleApp
{
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());
}
@@ -730,8 +727,8 @@ 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);
result.getCommand().where(EMP.GENDER.is(Gender.M));
@@ -744,6 +741,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/beans/Employee.java
b/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/beans/Employee.java
index bf44085..da1b5f1 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,7 +19,6 @@
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;
@@ -29,6 +28,8 @@ import org.apache.empire.db.DBCommand;
import org.apache.empire.db.DBContext;
import org.apache.empire.db.list.Bean;
import org.apache.empire.samples.db.SampleDB;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* This is an employee entity bean
@@ -37,6 +38,8 @@ import org.apache.empire.samples.db.SampleDB;
*/
public class Employee implements Bean<SampleDB>
{
+ private static final Logger log = LoggerFactory.getLogger(Employee.class);
+
private long id; // "ID"
private String firstname; // "FIRSTNAME"
private String lastname; // "LASTNAME"
@@ -63,7 +66,6 @@ public class Employee implements Bean<SampleDB>
* @param phoneNumber
* @param salary
* @param retired
- */
public Employee(int id, String firstname, String lastname, Date
dateOfBirth, int departmentId, String gender, String phoneNumber,
BigDecimal salary, boolean retired, Timestamp timestamp)
{
@@ -76,7 +78,10 @@ public class Employee implements Bean<SampleDB>
this.phoneNumber = phoneNumber;
this.salary = salary;
this.retired = retired;
+
+ log.info("Employee bean created using fields constructor");
}
+ */
/**
* Constructor using fields but without timestamp
@@ -84,7 +89,26 @@ public class Employee implements Bean<SampleDB>
public Employee(int id, String firstname, String lastname, Date
dateOfBirth, int departmentId, String gender, String phoneNumber,
BigDecimal salary, boolean retired)
{
- this(id, firstname, lastname, dateOfBirth, departmentId, gender,
phoneNumber, salary, retired, null);
+ 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;
+
+ log.info("Employee bean created using fields constructor without
timestamp");
+ }
+
+ /**
+ * Constructor using primary key fields
+ */
+ public Employee(int id)
+ {
+ this.id = id;
+ log.info("Employee bean created using primary key constructor");
}
/**
@@ -93,6 +117,7 @@ public class Employee implements Bean<SampleDB>
public Employee()
{
// Standard constructor
+ log.info("Employee bean created using standard constructor");
}
public long getId()
diff --git a/empire-db/src/main/java/org/apache/empire/commons/ObjectUtils.java
b/empire-db/src/main/java/org/apache/empire/commons/ObjectUtils.java
index f15154e..88f21c6 100644
--- a/empire-db/src/main/java/org/apache/empire/commons/ObjectUtils.java
+++ b/empire-db/src/main/java/org/apache/empire/commons/ObjectUtils.java
@@ -114,6 +114,10 @@ public final class ObjectUtils
throw new InvalidValueException(o);
if ((o instanceof String) && ((String)o).length()==0)
return true;
+ if ((o instanceof Object[]) && ((Object[])o).length==0)
+ return true;
+ if ((o instanceof Collection<?>) && ((Collection<?>)o).isEmpty())
+ return true;
// not empty
return false;
}
@@ -908,12 +912,32 @@ public final class ObjectUtils
*/
public static <T> List<T> convert(Class<T> t, Collection<? extends T>
source)
{
- List<T> target = new ArrayList<T>();
+ if (source==null)
+ return null;
+ List<T> target = new ArrayList<T>(source.size());
target.addAll(source);
return target;
}
/**
+ * Converts an array to a list
+ *
+ * @param t the type of the list items
+ * @param array the array to be converted
+ *
+ * @return the list
+ */
+ public static <T> List<T> arrayToList(Class<T> t, T[] array)
+ {
+ if (array==null)
+ return null;
+ List<T> list = new ArrayList<T>(array.length);
+ for (int i=0; i<array.length; i++)
+ list.add(array[i]);
+ return list;
+ }
+
+ /**
* Converts an Object array to a String array.
* @param objArray the object array to convert
* @param defValue default value which will be set for all null objects
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 fa54020..60407a1 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
@@ -340,8 +340,12 @@ public abstract class DBRowSet extends DBExpr implements
Entity
*/
public <T> void setBeanType(Class<T> beanType, DBBeanListFactory<T>
factory)
{
+ // create default factory if not provided
+ if (factory==null)
+ factory = new DBBeanListFactoryImpl<T>(beanType, getKeyColumns(),
getColumns());
+ // set
this.beanType = beanType;
- this.beanFactory = (beanFactory!=null ? beanFactory : new
DBBeanListFactoryImpl<T>(beanType, this.columns));
+ this.beanFactory = factory;
// set to global map
setRowsetForType(beanType, this);
}
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 f4c64ab..067b756 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
@@ -10,13 +10,13 @@ import java.util.List;
import org.apache.empire.commons.ObjectUtils;
import org.apache.empire.commons.Options;
import org.apache.empire.commons.StringUtils;
+import org.apache.empire.data.Column;
import org.apache.empire.data.DataType;
import org.apache.empire.data.list.DataListEntry;
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.CommandWithoutSelectException;
import org.apache.empire.db.exceptions.ConstraintViolationException;
import org.apache.empire.db.exceptions.QueryFailedException;
import org.apache.empire.db.exceptions.QueryNoResultException;
@@ -917,9 +917,9 @@ public class DBUtils implements DBContextAware
* @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)
+ protected <T> DBBeanListFactory<T> createDefaultBeanListFactory(Class<T>
beanType, Column[] keyColumns, List<? extends DBColumnExpr> selectColumns)
{
- return new DBBeanListFactoryImpl<T>(beanType, constructorParams);
+ return new DBBeanListFactoryImpl<T>(beanType, keyColumns,
selectColumns);
}
/**
@@ -933,7 +933,7 @@ public class DBUtils implements DBContextAware
@SuppressWarnings("unchecked")
DBBeanListFactory<T> factory =
(DBBeanListFactory<T>)rowset.getBeanFactory();
if (factory==null)
- factory =createDefaultBeanListFactory(beanType,
rowset.getColumns());
+ factory =createDefaultBeanListFactory(beanType,
rowset.getKeyColumns(), rowset.getColumns());
return factory;
}
@@ -1022,21 +1022,6 @@ public class DBUtils implements DBContextAware
{
return queryBeanList(cmd, factory, parent, 0, -1);
}
-
- /**
- * Queries a list of Java beans for a given command
- * @param cmd the query command
- * @param beanType the beanType
- * @param constructorParams (optional) the list of params used for the
bean constructor (optional, may be null)
- * @param parent (optional) the parent bean if any
- * @return the list of java beans
- */
- public <T> List<T> queryBeanList(DBCommand cmd, Class<T> beanType, List<?
extends DBColumnExpr> constructorParams, Object parent, int first, int pageSize)
- {
- if (!cmd.hasSelectExpr() && (constructorParams==null ||
constructorParams.isEmpty()))
- throw new CommandWithoutSelectException(cmd);
- return queryBeanList(cmd, createDefaultBeanListFactory(beanType,
constructorParams), parent, first, pageSize);
- }
/**
* Queries a list of Java beans for a given command
@@ -1055,21 +1040,6 @@ public class DBUtils implements DBContextAware
* Queries a list of Java beans for a given command
* @param cmd the query command
* @param beanType the beanType
- * @param constructorParams (optional) the params used for the bean
constructor
- * @param parent (optional) the parent bean if any
- * @return the list of java beans
- */
- public <T> List<T> queryBeanList(DBCommand cmd, Class<T> beanType, List<?
extends DBColumnExpr> constructorParams, Object parent)
- {
- if (!cmd.hasSelectExpr() && (constructorParams==null ||
constructorParams.isEmpty()))
- throw new CommandWithoutSelectException(cmd);
- return queryBeanList(cmd, createDefaultBeanListFactory(beanType,
constructorParams), parent, 0, -1);
- }
-
- /**
- * Queries a list of Java beans for a given command
- * @param cmd the query command
- * @param beanType the beanType
* @param parent (optional) the parent bean if any
* @return the list of java beans
*/
@@ -1079,7 +1049,7 @@ public class DBUtils implements DBContextAware
if (rowset!=null)
return queryBeanList(cmd, getRowsetBeanListFactory(beanType,
rowset), parent);
else
- return queryBeanList(cmd, beanType, cmd.getSelectExpressions(),
parent);
+ return queryBeanList(cmd, createDefaultBeanListFactory(beanType,
null, cmd.getSelectExpressions()), parent);
}
/**
@@ -1115,20 +1085,6 @@ public class DBUtils implements DBContextAware
/**
* Queries a single Java Bean for a given command
* @param cmd the query command
- * @param beanType the bean type
- * @param constructorParams (optional) the params used for the bean
constructor
- * @return the bean instance
- */
- public final <T> T queryBean(DBCommand cmd, Class<T> beanType, List<?
extends DBColumnExpr> constructorParams)
- {
- if (!cmd.hasSelectExpr() && (constructorParams==null ||
constructorParams.isEmpty()))
- throw new CommandWithoutSelectException(cmd);
- return queryBean(cmd, createDefaultBeanListFactory(beanType,
constructorParams));
- }
-
- /**
- * Queries a single Java Bean for a given command
- * @param cmd the query command
* @param beanType the beanType
* @param parent (optional) the parent bean if any
* @return the list of java beans
@@ -1139,7 +1095,7 @@ public class DBUtils implements DBContextAware
if (rowset!=null)
return queryBean(cmd, getRowsetBeanListFactory(beanType, rowset));
else
- return queryBean(cmd, beanType, cmd.getSelectExpressions());
+ return queryBean(cmd, createDefaultBeanListFactory(beanType, null,
cmd.getSelectExpressions()));
}
/**
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
index c98c1c5..ba87736 100644
---
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
@@ -24,12 +24,16 @@ import java.util.ArrayList;
import java.util.List;
import org.apache.empire.commons.ClassUtils;
+import org.apache.empire.commons.ObjectUtils;
+import org.apache.empire.data.Column;
+import org.apache.empire.db.DBColumn;
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;
+import org.apache.empire.exceptions.UnsupportedTypeException;
/**
* DBRecordListFactoryImpl
@@ -46,22 +50,21 @@ public class DBBeanListFactoryImpl<T> implements
DBBeanListFactory<T>
*/
@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;
+ { // find a suitable constructor (but not the default constructor!)
+ if (params==null || params.isEmpty())
+ return 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
+ return (Constructor<T>)
ClassUtils.findMatchingAccessibleConstructor(beanType, paramTypes);
+ }
+
+ @SuppressWarnings("unchecked")
+ protected static <T> Constructor<T> findBeanConstructor(Class<T> beanType)
+ { // find default constructor
+ return
(Constructor<T>)ClassUtils.findMatchingAccessibleConstructor(beanType, new
Class<?>[] {});
}
/*
@@ -69,43 +72,113 @@ public class DBBeanListFactoryImpl<T> implements
DBBeanListFactory<T>
*/
protected final Constructor<T> constructor;
protected final List<? extends DBColumnExpr> constructorParams;
+ protected final List<? extends DBColumnExpr> setterColumns;
/**
* 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
+ * @param constructor the constructor to be used to create the bean
+ * @param constructorParams (optional) the columns to be used for the
constructor. Must match the constructor!
+ * @param setterColumns (optional) the columns to be set through setter
methods. List may include constructorParams
*/
- public DBBeanListFactoryImpl(Constructor<T> constructor, List<? extends
DBColumnExpr> constructorParams)
+ public DBBeanListFactoryImpl(Constructor<T> constructor, List<? extends
DBColumnExpr> constructorParams, List<? extends DBColumnExpr> setterColumns)
{
this.constructor = constructor;
this.constructorParams = constructorParams;
+ this.setterColumns = setterColumns;
// Check constructor
if (constructor!=null && constructor.getParameterCount()>0 &&
(constructorParams==null ||
constructor.getParameterCount()<constructorParams.size()))
- throw new InvalidArgumentException("constructor", constructor);
+ throw new
InvalidArgumentException("constructor||constructorParams", 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
+ * @param beanType the bean type to be instantiated
+ * @param selectColumns (optional) the columns to be selected
*/
- public DBBeanListFactoryImpl(Class<T> beanType, List<? extends
DBColumnExpr> constructorParams)
+ public DBBeanListFactoryImpl(Class<T> beanType, List<? extends
DBColumnExpr> selectColumns)
{
- this(findBeanConstructor(beanType, constructorParams),
constructorParams);
+ Constructor<T> constructor = findBeanConstructor(beanType,
selectColumns);
+ if (constructor!=null)
+ { // construct with key columns
+ this.constructorParams = selectColumns;
+ this.setterColumns = null;
+ }
+ else
+ { // find default constructor
+ constructor = findBeanConstructor(beanType);
+ if (constructor==null)
+ throw new UnsupportedTypeException(beanType);
+ // use default constructor
+ this.constructorParams = null;
+ this.setterColumns = selectColumns;
+ }
+ this.constructor = constructor;
+ }
+
+ /**
+ * Constructs a DBRecordListFactoryImpl based on an DBRecord class
+ * @param beanType the bean type to be instantiated
+ * @param keyColumns (optional) the columns to be used for the constructor
+ * @param selectColumns (optional) the columns to be set through setter
methods. List may include constructorParams
+ */
+ public DBBeanListFactoryImpl(Class<T> beanType, List<? extends
DBColumnExpr> keyColumns, List<? extends DBColumnExpr> selectColumns)
+ {
+ Constructor<T> constructor = findBeanConstructor(beanType,
selectColumns);
+ if (constructor!=null)
+ { // construct with all columns
+ this.constructorParams = selectColumns;
+ this.setterColumns = null;
+ }
+ else if ((constructor = findBeanConstructor(beanType,
keyColumns))!=null)
+ { // construct with key columns
+ this.constructorParams = keyColumns;
+ this.setterColumns = selectColumns;
+ }
+ else
+ { // find default constructor
+ constructor = findBeanConstructor(beanType);
+ if (constructor==null)
+ throw new UnsupportedTypeException(beanType);
+ // use default constructor
+ this.constructorParams = null;
+ this.setterColumns = selectColumns;
+ }
+ this.constructor = constructor;
+ }
+
+ /**
+ * Constructs a DBRecordListFactoryImpl based on an DBRecord class
+ * @param beanType the bean type to be instantiated
+ * @param keyColumns (optional) the columns to be used for the
constructor. Important: Must be a DBColumn array!
+ * @param selectColumns (optional) the columns to be set through setter
methods. List may include constructorParams
+ */
+ public DBBeanListFactoryImpl(Class<T> beanType, Column[] keyColumns,
List<? extends DBColumnExpr> selectColumns)
+ {
+ this(beanType, ObjectUtils.arrayToList(DBColumn.class,
(DBColumn[])keyColumns), selectColumns);
}
@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);
+ if (constructorParams!=null)
+ { // select all columns which are not already selected
+ for (DBColumnExpr expr : constructorParams)
+ {
+ if (cmd.hasSelectExpr(expr)==false)
+ cmd.select(expr);
+ }
+ }
+ // check the rest of the columns
+ if (setterColumns!=null)
+ { // select all columns which are not already selected
+ for (DBColumnExpr expr : setterColumns)
+ {
+ if (constructorParams!=null &&
constructorParams.contains(expr))
+ continue; // already added
+ if (cmd.hasSelectExpr(expr)==false)
+ cmd.select(expr);
+ }
}
}
@@ -148,7 +221,7 @@ public class DBBeanListFactoryImpl<T> implements
DBBeanListFactory<T>
@Override
public void completeQuery(List<T> list)
{
-
+ /* Nothing */
}
}