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 */
     }
     
 }

Reply via email to