This is an automated email from the ASF dual-hosted git repository.

doebele pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/empire-db.git


The following commit(s) were added to refs/heads/master by this push:
     new c6166e8c EMPIREDB-444 New class ValueUtils to override value type 
conversion
c6166e8c is described below

commit c6166e8cc6811685122939a5445956241c938fc8
Author: Rainer Döbele <[email protected]>
AuthorDate: Thu Oct 24 14:47:58 2024 +0200

    EMPIREDB-444
    New class ValueUtils to override value type conversion
---
 .../org/apache/empire/commons/ObjectUtils.java     | 605 ++++--------------
 .../commons/{ObjectUtils.java => ValueUtils.java}  | 699 ++++-----------------
 .../main/java/org/apache/empire/db/DBCmdParam.java |  27 +-
 .../java/org/apache/empire/db/DBRecordBase.java    |  12 +-
 .../main/java/org/apache/empire/db/DBRowSet.java   |   2 -
 .../java/org/apache/empire/db/DBSQLBuilder.java    |  19 +-
 6 files changed, 250 insertions(+), 1114 deletions(-)

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 03fb6d47..015e0339 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
@@ -18,14 +18,11 @@
  */
 package org.apache.empire.commons;
 
+import java.io.Serializable;
 import java.math.BigDecimal;
-import java.math.BigInteger;
 import java.text.ParseException;
-import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
-import java.time.format.DateTimeParseException;
-import java.time.temporal.Temporal;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -35,26 +32,31 @@ import java.util.Locale;
 
 import org.apache.commons.beanutils.MethodUtils;
 import org.apache.empire.data.ColumnExpr;
-import org.apache.empire.db.expr.column.DBValueExpr;
+import org.apache.empire.data.DataType;
 import org.apache.empire.exceptions.InvalidArgumentException;
-import org.apache.empire.exceptions.InvalidValueException;
-import org.apache.empire.exceptions.ItemNotFoundException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * This class contains common functions for comparing and converting values of 
type Object. 
+ * This class contains common functions for comparing and converting values 
from and to the database
+ * As well as other useful Array and List related functions. 
  * 
+ * Value and value related conversion functions my be overridden by setting a 
customized version of the
+ * ValueUtils object via 
+ *      setValueUtils(ValueUtils valueUtils)
  */
 public final class ObjectUtils
 {
+    // Logger
+    private static final Logger log = 
LoggerFactory.getLogger(ObjectUtils.class);
+    
     /**
      * This class explicitly defines that an Object has not been assigned a 
value.<BR>
      * This may be used in cases where the value of null may be a valid value.
      */
-    private static final class NoValue // *Deprecated* implements Serializable
+    private static final class NoValue implements Serializable
     {
-        // *Deprecated* private static final long serialVersionUID = 1L;
+        private static final long serialVersionUID = 1L;
         private NoValue()
         { /* dummy */
         }
@@ -71,37 +73,28 @@ public final class ObjectUtils
      */
     public static final NoValue NO_VALUE = new NoValue();
     
-    // Logger
-    private static final Logger log = 
LoggerFactory.getLogger(ObjectUtils.class);
-
-    private static final String DATE_FORMAT = "yyyy-MM-dd";
-       private static final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
-       
-    // DateOnly Formatter
-    private static final ThreadLocal<SimpleDateFormat> dateOnlyFormatter = new 
ThreadLocal<SimpleDateFormat>() {
-        @Override
-        protected SimpleDateFormat initialValue()
-        {
-            return new SimpleDateFormat(DATE_FORMAT);
-        }
-    };
+    /**
+     * The instance of ValueUtils to be used for value type conversion
+     */
+    static private ValueUtils valueUtils = new ValueUtils();
+    
+    public static ValueUtils getValueUtils()
+    {
+        return valueUtils;
+    }
 
-    // DateTime Formatter
-    private static final ThreadLocal<SimpleDateFormat> dateTimeFormatter = new 
ThreadLocal<SimpleDateFormat>() {
-        @Override
-        protected SimpleDateFormat initialValue()
-        {
-            return new SimpleDateFormat(DATETIME_FORMAT);
-        }
-    };
+    public static void setValueUtils(ValueUtils valueUtils)
+    {
+        ObjectUtils.valueUtils = valueUtils;
+    }
 
-    // Interal literal for NULL
-    private static final String NULL = "NULL";
-    
+    /**
+     * Private Constructor
+     * Static functions only
+     * No instance may be created
+     */
     private ObjectUtils()
     {
-        // Static Function only
-        // No instance may be created
     }
     
     /**
@@ -112,20 +105,7 @@ public final class ObjectUtils
      */
     public static boolean isEmpty(Object o)
     {
-        if (o==null)
-            return true;
-        if (o==NO_VALUE)
-            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;
-        if (o instanceof DBValueExpr)
-            return isEmpty(((DBValueExpr)o).getValue());
-        // not empty
-        return false;
+        return valueUtils.isEmpty(o);
     }
     
     /**
@@ -146,18 +126,7 @@ public final class ObjectUtils
      */
     public static boolean isZero(Number value)
     {
-        if (value==null)
-            return true;
-        if (value instanceof BigDecimal)
-            return (BigDecimal.ZERO.compareTo((BigDecimal)value) == 0);
-        if (value instanceof Float)
-            return (((Float) value).compareTo(0.0f)==0);
-        if (value instanceof Double)
-            return (((Double) value).compareTo(0.0d)==0);
-        if (value instanceof Long)
-            return (value.longValue()==0l);
-        // default: check int value
-        return (value.intValue()==0);
+        return valueUtils.isZero(value);
     }
 
     /**
@@ -177,12 +146,7 @@ public final class ObjectUtils
      */
     public static int lengthOf(Object o)
     {
-        if (o==null || o==NO_VALUE)
-            return 0;
-        if ((o instanceof String))
-            return ((String)o).length();
-        // convert
-        return o.toString().length();
+        return valueUtils.lengthOf(o);
     }
     
     /**
@@ -193,113 +157,9 @@ public final class ObjectUtils
      * 
      * @return true if both objects are equal or false otherwise
      */
-    @SuppressWarnings("unchecked")
     public static boolean compareEqual(Object o1, Object o2)
     {
-       // simple case
-       if (o1==o2)
-               return true;
-        // Check for Empty Values
-        if (isEmpty(o1))
-            return isEmpty(o2);
-        if (isEmpty(o2))
-            return isEmpty(o1);
-        // Check classes
-        if (o1.getClass().equals(o2.getClass()))
-        {   // Check simple array
-            if ((o1 instanceof Object[]) && (o2 instanceof Object[])) 
-                return compareEqual((Object[])o1, (Object[])o2);
-            // Check if object implements comparable
-            if (o1 instanceof Comparable)
-                return (((Comparable<Object>)o1).compareTo(o2)==0);
-            else
-                return o1.equals(o2);
-        }
-        // Classes don't match
-        // Use equal check first
-        if (o1.equals(o2) || o2.equals(o1))
-            return true;
-        // Compare Numbers
-        if (o1 instanceof Number && o2 instanceof Number)
-        {   // boolean test = obj1.equals(obj2);
-            double d1 = ((Number)o1).doubleValue();
-            double d2 = ((Number)o2).doubleValue(); 
-            return (d1==d2);
-        }
-        // Compare Date with LocalDate / LocalDateTime
-        if (o1 instanceof Temporal && o2 instanceof Date)
-        {   // swap
-            Object tmp = o2; o2 = o1; o1 = tmp; 
-        }
-        if (o1 instanceof Date && o2 instanceof LocalDate)
-            return o1.equals(DateUtils.toDate((LocalDate)o2));
-        if (o1 instanceof Date && o2 instanceof LocalDateTime)
-            return o1.equals(DateUtils.toDate((LocalDateTime)o2));
-        // Enum
-        if (o1 instanceof Enum<?>)
-        {   // Special enum handling   
-            if (o2 instanceof Number)
-                return ((Enum<?>)o1).ordinal()==((Number)o2).intValue();
-            // Compare Strings
-            String strVal = StringUtils.coalesce(getString((Enum<?>)o1), NULL);
-            return strVal.equals(getString(o2));
-        }
-        else if (o2 instanceof Enum<?>)
-        {   // Special enum handling   
-            if (o1 instanceof Number)
-                return ((Enum<?>)o2).ordinal()==((Number)o1).intValue();
-            // Compare Strings
-            String strVal = StringUtils.coalesce(getString((Enum<?>)o2), 
NULL); 
-            return strVal.equals(getString(o1));
-        }
-        // Compare Strings
-        if (o1 instanceof String)
-            return ((String)o1).equals(o2.toString());
-        if (o2 instanceof String)
-            return ((String)o2).equals(o1.toString());
-        // Not equal
-        return false;
-    }
-
-    /**
-     * Compares two arrays for equality
-     *
-     * @param array1    the first array
-     * @param array2    the second array
-     *
-     * @return true if both arrays are equal or false otherwise
-     */
-    public static boolean compareEqual(Object[] array1, Object[] array2)
-    {   // Compare Length
-        int len1 = (array1!=null ? array1.length : 0);
-        int len2 = (array2!=null ? array2.length : 0);
-        if (len1!= len2)
-            return false;
-        // Compare Key Values
-        for (int i = 0; i < len1; i++)
-        {   // Check String Values
-            if (!ObjectUtils.compareEqual(array1[i], array2[i]))
-                return false;
-        }
-        return true;
-    }
-    
-    /**
-     * Compares two ColumnExpr for equality
-     *
-     * @param expr a column expression
-     * @param other a column expression
-     *
-     * @return true if both expressions are equal or false otherwise
-     */
-    public static boolean compareEqual(ColumnExpr expr, ColumnExpr other)
-    {
-        if (isWrapper(other) && !isWrapper(expr))
-            return expr.equals(unwrap(other));
-        else  if (!isWrapper(other) && isWrapper(expr))
-            return unwrap(expr).equals(other);
-        // both wrapped or both unwrapped
-        return expr.equals(other);
+        return valueUtils.compareEqual(o1, o2);
     }
     
     /**
@@ -310,46 +170,9 @@ public final class ObjectUtils
      * 
      * @return true if both objects are equal or false otherwise
      */
-    @SuppressWarnings("unchecked")
     public static int compare(Object o1, Object o2)
     {
-        // simple case
-        if (o1==o2)
-            return 0;
-        // Check for Empty Values
-        if (isEmpty(o1))
-            return isEmpty(o2) ? 0 : -1;
-        if (isEmpty(o2))
-            return isEmpty(o1) ? 0 :  1;
-        // Check classes
-        if (o1.getClass().equals(o2.getClass()))
-        {   // Check if object implements comparable
-            if (o1 instanceof Comparable)
-                return ((Comparable<Object>)o1).compareTo(o2);
-            if (o2 instanceof Comparable)
-                return ((Comparable<Object>)o2).compareTo(o1);
-        }    
-        // Use equal check first
-        if (o1.equals(o2) || o2.equals(o1))
-            return 0;
-        // Compare Numbers
-        if (o1 instanceof Number && o2 instanceof Number)
-        {   // boolean test = obj1.equals(obj2);
-            double d1 = ((Number)o1).doubleValue();
-            double d2 = ((Number)o2).doubleValue();
-            return ((d1<d2) ? -1 : ((d1>d2) ? 1 : 0));
-        }
-        // Compare Date with LocalDate / LocalDateTime
-        if (o1 instanceof Temporal && o2 instanceof Date)
-        {   // swap
-            Object tmp = o2; o2 = o1; o1 = tmp; 
-        }
-        if (o1 instanceof Date && o2 instanceof LocalDate)
-            return compare(o1, DateUtils.toDate((LocalDate)o2));
-        if (o1 instanceof Date && o2 instanceof LocalDateTime)
-            return compare(o1, DateUtils.toDate((LocalDateTime)o2));
-        // Compare Strings
-        return o1.toString().compareTo(o2.toString());
+        return valueUtils.compare(o1, o2);
     }
     
     /**
@@ -371,13 +194,7 @@ public final class ObjectUtils
      */
     public static int toInteger(Object v)
     {
-        if (ObjectUtils.isEmpty(v))
-            return 0;
-        if (v instanceof Number)
-            return ((Number)v).intValue();
-        // Try to convert
-        String str = v.toString();
-        return Integer.parseInt(str);
+        return valueUtils.toInteger(v);
     }
     
     /**
@@ -397,7 +214,7 @@ public final class ObjectUtils
         {   // Try to convert
             return toInteger(v);
         } catch (NumberFormatException e) {
-               log.error(String.format("Cannot convert value [%s] to int", v));
+            log.error(String.format("Cannot convert value [%s] to int", v));
             return defValue;
         }
     }
@@ -421,13 +238,7 @@ public final class ObjectUtils
      */
     public static long toLong(Object v)
     {
-        if (ObjectUtils.isEmpty(v))
-            return 0;
-        if (v instanceof Number)
-            return ((Number)v).longValue();
-        // Try to convert
-        String str = v.toString();
-        return Long.parseLong(str);
+        return valueUtils.toLong(v);
     }
     
     /**
@@ -447,7 +258,7 @@ public final class ObjectUtils
         {   // Try to convert
             return toLong(v);
         } catch (NumberFormatException e) {
-               log.error(String.format("Cannot convert value [%s] to long", 
v));
+            log.error(String.format("Cannot convert value [%s] to long", v));
             return defValue;
         }
     }
@@ -471,14 +282,7 @@ public final class ObjectUtils
      */
     public static double toDouble(Object v)
     {
-        // Get Double value
-        if (ObjectUtils.isEmpty(v))
-            return 0.0;
-        if (v instanceof Number)
-            return ((Number)v).doubleValue();
-        // parse String for Integer value
-        String val = v.toString(); 
-        return Double.parseDouble(val);
+        return valueUtils.toDouble(v);
     }
     
     /**
@@ -522,26 +326,7 @@ public final class ObjectUtils
      */
     public static BigDecimal toDecimal(Object v)
     {
-        // Get Double value
-        if (ObjectUtils.isEmpty(v))
-            return null;
-        if (v instanceof BigDecimal)
-            return ((BigDecimal)v);
-        // Find a suitable converter
-        if (v instanceof Number)
-        {   // check other number types
-            if (v instanceof BigInteger)
-                return new BigDecimal((BigInteger)v);
-            if (v instanceof Integer)
-                return BigDecimal.valueOf(((Number)v).intValue());
-            if (v instanceof Long)
-                return BigDecimal.valueOf(((Number)v).longValue());
-            // Default: convert via double
-            return BigDecimal.valueOf(((Number)v).doubleValue());
-        }
-        // parse String for Integer value
-        // Last-Chance > Try a string conversion
-        return new BigDecimal(v.toString());
+        return valueUtils.toDecimal(v);
     }
     
     /**
@@ -590,21 +375,7 @@ public final class ObjectUtils
      */
     public static boolean getBoolean(Object v, boolean defValue)
     {
-        // Get Boolean value
-        if (ObjectUtils.isEmpty(v))
-            return defValue;
-        if (v instanceof Boolean)
-            return ((Boolean)v).booleanValue();
-        if (v instanceof Number)
-            return (((Number)v).intValue()!=0);
-        if (v instanceof String) {
-            String val = ((String)v);
-            if (StringUtils.isEmpty(val))
-                return defValue;
-            // check for allowed true values
-            return (val.equalsIgnoreCase("true") || val.equalsIgnoreCase("Y"));
-        }
-        return defValue;
+        return valueUtils.getBoolean(v, defValue);
     }
     
     /**
@@ -625,52 +396,9 @@ public final class ObjectUtils
      * @param value the value to convert
      * @return the enum
      */
-    @SuppressWarnings("unchecked")
     public static <T extends Enum<?>> T getEnum(Class<T> enumType, Object 
value)
-    {   // check for null
-        if (isEmpty(value))
-            return null;
-        // check enum
-        if (value instanceof Enum<?>)
-        {   // already an enum: Check type
-            if (value.getClass().equals(enumType))
-                return (T)value;
-            // try to match names
-            value = ((Enum<?>)value).name();
-        }
-        // check column data type
-        boolean numeric = (value instanceof Number);
-        T[] items = enumType.getEnumConstants();
-        if (items.length>0 && (items[0] instanceof EnumValue))
-        {   // custom conversion
-            for (T e : items)
-            {
-                Object eVal = ((EnumValue)e).toValue(numeric);
-                if (ObjectUtils.compareEqual(eVal, value))
-                    return e;
-            }
-            // error: not found
-            throw new ItemNotFoundException(StringUtils.toString(value));
-        }
-        else if (numeric)
-        {   // by ordinal
-            int ordinal = ((Number)value).intValue();
-            // check range
-            if (ordinal<0 || ordinal>=items.length)
-                throw new ItemNotFoundException(String.valueOf(ordinal));
-            // return enum
-            return items[ordinal]; 
-        }
-        else
-        {   // by name
-            String name = StringUtils.toString(value);
-            // find name
-            for (T e : items)
-                if (e.name().equals(name))
-                    return e;
-            // error: not found
-            throw new ItemNotFoundException(name);
-        }
+    {
+        return valueUtils.getEnum(enumType, value);
     }
 
     /**
@@ -681,16 +409,8 @@ public final class ObjectUtils
      * @return the enum
      */
     public static <T extends Enum<?>> T getEnumByName(Class<T> enumType, 
String name)
-    {   // check for null
-        if (isEmpty(name))
-            return null;
-        // check column data type
-        T[] items = enumType.getEnumConstants();
-        for (T e : items)
-            if (e.name().equals(name))
-                return e;
-        // error: not found
-        throw new ItemNotFoundException(name);
+    {
+        return valueUtils.getEnumByName(enumType, name);
     }
     
     /**
@@ -701,11 +421,7 @@ public final class ObjectUtils
      */
     public static Object getEnumValue(Enum<?> enumValue, boolean isNumeric)
     {
-        // convert
-        if (enumValue instanceof EnumValue)
-            return ((EnumValue)enumValue).toValue(isNumeric);
-        // default
-        return (isNumeric ? enumValue.ordinal() : getString(enumValue));
+        return valueUtils.getEnumValue(enumValue, isNumeric);
     }
     
     /**
@@ -715,14 +431,7 @@ public final class ObjectUtils
      */
     public static String getString(Enum<?> enumValue)
     {
-        // convert
-        if (enumValue instanceof EnumValue)
-            return StringUtils.toString(((EnumValue)enumValue).toValue(false));
-        /* special case */
-        if (enumValue==null || enumValue.name().equals(NULL))
-            return null;
-        /* use name */
-        return enumValue.name();
+        return valueUtils.getString(enumValue);
     }
     
     /**
@@ -732,19 +441,7 @@ public final class ObjectUtils
      */
     public static String getString(Object value)
     {
-        if (value==null)
-            return null;
-        if (value instanceof String)
-            return (String)value;
-        if (value==NO_VALUE)
-            throw new InvalidValueException(value);
-        // convert
-        if (value instanceof Enum<?>)
-            return getString((Enum<?>)value);
-        if (value instanceof Date)
-            return formatDate((Date)value, true);
-        // default
-        return value.toString();
+        return valueUtils.getString(value);
     }
     
     /**
@@ -757,21 +454,7 @@ public final class ObjectUtils
     public static Date toDate(Object v)
         throws ParseException
     {
-        // Get DateTime value
-        if (ObjectUtils.isEmpty(v))
-            return null;
-        if (v instanceof java.util.Date)
-            return ((java.util.Date)v);
-        if (v instanceof java.time.LocalDate)
-            return DateUtils.toDate((LocalDate)v);
-        if (v instanceof java.time.LocalDateTime)
-            return DateUtils.toDate((LocalDateTime)v);
-        // Convert from String
-        String str = v.toString();
-        if (str.length() > 10)
-            return dateTimeFormatter.get().parse(str);
-        else
-            return dateOnlyFormatter.get().parse(str);
+        return valueUtils.toDate(v);
     }
     
     /**
@@ -784,35 +467,7 @@ public final class ObjectUtils
      */
     public static Date getDate(Object v, Locale locale)
     {
-        // Get DateTime value
-        if (ObjectUtils.isEmpty(v))
-            return null;
-        if (v instanceof Date)
-            return ((Date)v);
-        if (v instanceof java.time.LocalDate)
-            return DateUtils.toDate((LocalDate)v);
-        if (v instanceof java.time.LocalDateTime)
-            return DateUtils.toDate((LocalDateTime)v);
-        // Get Calendar
-        if (v instanceof Number)
-        {   // Get Date from a number
-            long l = ((Number)v).longValue();
-            if (l==0)
-                return DateUtils.getDateNow();
-            // Year or full date/time?
-            /*
-            if (l<10000)
-            {   // Year only
-                Calendar calendar = 
Calendar.getInstance(getSafeLocale(locale));
-                calendar.set((int)l, 1, 1);
-                return calendar.getTime();
-            }
-            */
-            // Date from long
-            return new Date(l);
-        }
-        // Try to parse
-        return DateUtils.parseDate(v.toString(), locale);
+        return valueUtils.getDate(v, locale);
     }
     
     /**
@@ -823,26 +478,7 @@ public final class ObjectUtils
      */
     public static Date getDate(Object v)
     {
-        // Get DateTime value
-        if (ObjectUtils.isEmpty(v))
-            return null;
-        if (v instanceof java.util.Date)
-            return ((java.util.Date)v);
-        if (v instanceof java.time.LocalDate)
-            return DateUtils.toDate((LocalDate)v);
-        if (v instanceof java.time.LocalDateTime)
-            return DateUtils.toDate((LocalDateTime)v);
-        // Convert from String
-        String str = v.toString();
-        try
-        {   if (str.length() > 10)
-                return dateTimeFormatter.get().parse(str);
-            else
-                return dateOnlyFormatter.get().parse(str);
-        } catch (ParseException e) {
-            log.error(String.format("Cannot convert value [%s] to Date", str), 
e);
-            return null;
-        }
+        return valueUtils.getDate(v);
     }
     
     /**
@@ -853,28 +489,7 @@ public final class ObjectUtils
      */
     public static LocalDate getLocalDate(Object v)
     {
-        // Get DateTime value
-        if (ObjectUtils.isEmpty(v))
-            return null;
-        if (v instanceof java.time.LocalDate)
-            return (LocalDate)v;
-        if (v instanceof java.time.LocalDateTime)
-            return ((LocalDateTime)v).toLocalDate();
-        if (v instanceof java.sql.Timestamp)
-            return ((java.sql.Timestamp)v).toLocalDateTime().toLocalDate();
-        if (v instanceof java.sql.Date)
-            return ((java.sql.Date)v).toLocalDate();
-        if (v instanceof java.util.Date)
-            return DateUtils.toLocalDate((Date)v);
-        // Convert from String
-        String str = v.toString();
-        try
-        {   // DateTimeFormatter ISO_LOCAL_DATE
-            return LocalDate.parse(str);
-        } catch (DateTimeParseException e) {
-            log.error(String.format("Cannot convert value [%s] to LocalDate", 
str), e);
-            return null;
-        }
+        return valueUtils.getLocalDate(v);
     }
     
     /**
@@ -885,28 +500,7 @@ public final class ObjectUtils
      */
     public static LocalDateTime getLocalDateTime(Object v)
     {
-        // Get DateTime value
-        if (ObjectUtils.isEmpty(v))
-            return null;
-        if (v instanceof java.time.LocalDate)
-            return ((LocalDate)v).atStartOfDay();
-        if (v instanceof java.time.LocalDateTime)
-            return (LocalDateTime)v;
-        if (v instanceof java.sql.Timestamp)
-            return ((java.sql.Timestamp)v).toLocalDateTime();
-        if (v instanceof java.sql.Date)
-            return ((java.sql.Date)v).toLocalDate().atStartOfDay();
-        if (v instanceof java.util.Date)
-            return DateUtils.toLocalDateTime((Date)v);
-        // Convert from String
-        String str = v.toString();
-        try
-        {   // DateTimeFormatter.ISO_LOCAL_DATE_TIME
-            return LocalDateTime.parse(str);
-        } catch (DateTimeParseException e) {
-            log.error(String.format("Cannot convert value [%s] to 
LocalDateTime", str), e);
-            return null;
-        }
+        return valueUtils.getLocalDateTime(v);
     }
     
     /**
@@ -919,12 +513,7 @@ public final class ObjectUtils
      */
     public static String formatDate(Date date, boolean withTime)
     {
-        if (date==null)
-            return null;
-       if (withTime)
-               return dateTimeFormatter.get().format(date);
-       else
-               return dateOnlyFormatter.get().format(date);
+        return valueUtils.formatDate(date, withTime);
     }
     
     /**
@@ -938,39 +527,22 @@ public final class ObjectUtils
      * 
      * @throws ClassCastException if the object is not null and is not 
assignable to the type T.
      */
-    @SuppressWarnings("unchecked")
     public static <T> T convert(Class<T> c, Object v)
         throws ClassCastException
     {
-        if (v==null || c.isInstance(v))
-            return (T)v;
-        if (v==NO_VALUE)
-            throw new InvalidValueException(v);
-        // Get Class form Primitive Type
-        if (c.isPrimitive())
-        {   // Get's the Java Class representing the primitive type
-            c = (Class<T>) MethodUtils.getPrimitiveWrapper(c);
-        }    
-        // Convert
-        if (c.isEnum())
-        {   // convert to enum
-            Object ev = getEnum((Class<? extends Enum<?>>)c, v); 
-            return (T)ev;
-        }
-        if (c.isAssignableFrom(Boolean.class))
-            return c.cast(getBoolean(v));
-        if (c.isAssignableFrom(Integer.class))
-            return c.cast(getInteger(v));
-        if (c.isAssignableFrom(Long.class))
-            return c.cast(getLong(v));
-        if(c.isAssignableFrom(Double.class))
-               return c.cast(getDouble(v));
-        if(c.isAssignableFrom(BigDecimal.class))
-            return c.cast(getDecimal(v));
-        if (c.isAssignableFrom(String.class))
-            return c.cast(v.toString());
-        // other
-        return c.cast(v);
+        return valueUtils.convert(c, v);
+    }
+
+    /**
+     * Converts a value to a specific DataType
+     * The returned value is used for generating SQL statements
+     * @param dataType the target data type
+     * @param value the value to convert
+     * @return the value to be used in SQL statements
+     */
+    public static Object convertValue(DataType type, Object value)
+    {
+        return valueUtils.convertValue(type, value);
     }
 
     /**
@@ -1017,6 +589,47 @@ public final class ObjectUtils
         // Not compatible
         return false;
     }
+
+    /**
+     * Compares two arrays for equality
+     *
+     * @param array1    the first array
+     * @param array2    the second array
+     *
+     * @return true if both arrays are equal or false otherwise
+     */
+    public static boolean compareEqual(Object[] array1, Object[] array2)
+    {   // Compare Length
+        int len1 = (array1!=null ? array1.length : 0);
+        int len2 = (array2!=null ? array2.length : 0);
+        if (len1!= len2)
+            return false;
+        // Compare Key Values
+        for (int i = 0; i < len1; i++)
+        {   // Check String Values
+            if (!ObjectUtils.compareEqual(array1[i], array2[i]))
+                return false;
+        }
+        return true;
+    }
+    
+    /**
+     * Compares two ColumnExpr for equality
+     *
+     * @param expr a column expression
+     * @param other a column expression
+     *
+     * @return true if both expressions are equal or false otherwise
+     */
+    public static boolean compareEqual(ColumnExpr expr, ColumnExpr other)
+    {
+        if (isWrapper(other) && !isWrapper(expr))
+            return expr.equals(unwrap(other));
+        else  if (!isWrapper(other) && isWrapper(expr))
+            return unwrap(expr).equals(other);
+        // both wrapped or both unwrapped
+        return expr.equals(other);
+    }
     
     /**
      * Generic conversion function that will convert a list to another list 
type.
diff --git a/empire-db/src/main/java/org/apache/empire/commons/ObjectUtils.java 
b/empire-db/src/main/java/org/apache/empire/commons/ValueUtils.java
similarity index 53%
copy from empire-db/src/main/java/org/apache/empire/commons/ObjectUtils.java
copy to empire-db/src/main/java/org/apache/empire/commons/ValueUtils.java
index 03fb6d47..9385365b 100644
--- a/empire-db/src/main/java/org/apache/empire/commons/ObjectUtils.java
+++ b/empire-db/src/main/java/org/apache/empire/commons/ValueUtils.java
@@ -26,59 +26,39 @@ import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeParseException;
 import java.time.temporal.Temporal;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Date;
-import java.util.List;
 import java.util.Locale;
 
 import org.apache.commons.beanutils.MethodUtils;
-import org.apache.empire.data.ColumnExpr;
+import org.apache.empire.data.DataType;
 import org.apache.empire.db.expr.column.DBValueExpr;
-import org.apache.empire.exceptions.InvalidArgumentException;
 import org.apache.empire.exceptions.InvalidValueException;
 import org.apache.empire.exceptions.ItemNotFoundException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * This class contains common functions for comparing and converting values of 
type Object. 
+ * This class allows to customize value type conversion as well as other value 
related functions.
+ * The functions and methods are called indirectly via the corresponding 
static functions in the ObjectUtils class.
  * 
+ * You may create your own derived class and overwrite the methods.
+ * In order to activate your ValueUtils implementation use the static function
+ * 
+ *      OjectUtils.setValueUtils(myValueUtils) 
+ * 
+ * @author doebele
  */
-public final class ObjectUtils
+public class ValueUtils
 {
-    /**
-     * This class explicitly defines that an Object has not been assigned a 
value.<BR>
-     * This may be used in cases where the value of null may be a valid value.
-     */
-    private static final class NoValue // *Deprecated* implements Serializable
-    {
-        // *Deprecated* private static final long serialVersionUID = 1L;
-        private NoValue()
-        { /* dummy */
-        }
-        @Override
-        public String toString()
-        {
-               return "[NO-VALUE]";
-        }
-    }
-    
-    /**
-     * Constant that defines a object of type NoValue.
-     * This may be used in cases where the value of null is a valid value.
-     */
-    public static final NoValue NO_VALUE = new NoValue();
-    
     // Logger
-    private static final Logger log = 
LoggerFactory.getLogger(ObjectUtils.class);
+    private static final Logger log = 
LoggerFactory.getLogger(ValueUtils.class);
 
-    private static final String DATE_FORMAT = "yyyy-MM-dd";
-       private static final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
-       
+    protected static final String DATE_FORMAT = "yyyy-MM-dd";
+    protected static final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
+    
     // DateOnly Formatter
-    private static final ThreadLocal<SimpleDateFormat> dateOnlyFormatter = new 
ThreadLocal<SimpleDateFormat>() {
+    protected static final ThreadLocal<SimpleDateFormat> dateOnlyFormatter = 
new ThreadLocal<SimpleDateFormat>() {
         @Override
         protected SimpleDateFormat initialValue()
         {
@@ -87,21 +67,17 @@ public final class ObjectUtils
     };
 
     // DateTime Formatter
-    private static final ThreadLocal<SimpleDateFormat> dateTimeFormatter = new 
ThreadLocal<SimpleDateFormat>() {
+    protected static final ThreadLocal<SimpleDateFormat> dateTimeFormatter = 
new ThreadLocal<SimpleDateFormat>() {
         @Override
         protected SimpleDateFormat initialValue()
         {
             return new SimpleDateFormat(DATETIME_FORMAT);
         }
     };
-
-    // Interal literal for NULL
-    private static final String NULL = "NULL";
     
-    private ObjectUtils()
+    protected ValueUtils()
     {
-        // Static Function only
-        // No instance may be created
+        /* subclass to override */
     }
     
     /**
@@ -110,11 +86,11 @@ public final class ObjectUtils
      * @param o the object to check
      * @return true if the Object is null or if its an empty string. 
      */
-    public static boolean isEmpty(Object o)
+    public boolean isEmpty(Object o)
     {
         if (o==null)
             return true;
-        if (o==NO_VALUE)
+        if (o==ObjectUtils.NO_VALUE)
             throw new InvalidValueException(o);
         if ((o instanceof String) && ((String)o).length()==0)
             return true;
@@ -128,23 +104,12 @@ public final class ObjectUtils
         return false;
     }
     
-    /**
-     * Checks whether an object has a value.
-     * A Object is considered to have a value if it is not null and not an 
empty string 
-     * @param o the object to check
-     * @return true if the Object is neither null nor an empty string. 
-     */
-    public static boolean isNotEmpty(Object o)
-    {
-        return !isEmpty(o);
-    }
-    
     /**
      * Checks whether a number is null or zero
      * @param value the number to check
      * @return true if the value is null or zero 
      */
-    public static boolean isZero(Number value)
+    public boolean isZero(Number value)
     {
         if (value==null)
             return true;
@@ -159,31 +124,6 @@ public final class ObjectUtils
         // default: check int value
         return (value.intValue()==0);
     }
-
-    /**
-     * Checks whether a number is NOT null or zero
-     * @param value the number to check
-     * @return true if the value is NOT null or zero 
-     */
-    public static boolean isNonZero(Number value)
-    {
-        return !isZero(value);
-    }
-    
-    /**
-     * returns the string length of an object
-     * @param o the object to check
-     * @return the string length of the object
-     */
-    public static int lengthOf(Object o)
-    {
-        if (o==null || o==NO_VALUE)
-            return 0;
-        if ((o instanceof String))
-            return ((String)o).length();
-        // convert
-        return o.toString().length();
-    }
     
     /**
      * Compares two objects for equality 
@@ -194,11 +134,11 @@ public final class ObjectUtils
      * @return true if both objects are equal or false otherwise
      */
     @SuppressWarnings("unchecked")
-    public static boolean compareEqual(Object o1, Object o2)
+    public boolean compareEqual(Object o1, Object o2)
     {
-       // simple case
-       if (o1==o2)
-               return true;
+        // simple case
+        if (o1==o2)
+            return true;
         // Check for Empty Values
         if (isEmpty(o1))
             return isEmpty(o2);
@@ -208,7 +148,7 @@ public final class ObjectUtils
         if (o1.getClass().equals(o2.getClass()))
         {   // Check simple array
             if ((o1 instanceof Object[]) && (o2 instanceof Object[])) 
-                return compareEqual((Object[])o1, (Object[])o2);
+                return compareEqual(o1, o2);
             // Check if object implements comparable
             if (o1 instanceof Comparable)
                 return (((Comparable<Object>)o1).compareTo(o2)==0);
@@ -241,7 +181,7 @@ public final class ObjectUtils
             if (o2 instanceof Number)
                 return ((Enum<?>)o1).ordinal()==((Number)o2).intValue();
             // Compare Strings
-            String strVal = StringUtils.coalesce(getString((Enum<?>)o1), NULL);
+            String strVal = StringUtils.coalesce(getString((Enum<?>)o1), 
StringUtils.NULL);
             return strVal.equals(getString(o2));
         }
         else if (o2 instanceof Enum<?>)
@@ -249,7 +189,7 @@ public final class ObjectUtils
             if (o1 instanceof Number)
                 return ((Enum<?>)o2).ordinal()==((Number)o1).intValue();
             // Compare Strings
-            String strVal = StringUtils.coalesce(getString((Enum<?>)o2), 
NULL); 
+            String strVal = StringUtils.coalesce(getString((Enum<?>)o2), 
StringUtils.NULL); 
             return strVal.equals(getString(o1));
         }
         // Compare Strings
@@ -260,47 +200,6 @@ public final class ObjectUtils
         // Not equal
         return false;
     }
-
-    /**
-     * Compares two arrays for equality
-     *
-     * @param array1    the first array
-     * @param array2    the second array
-     *
-     * @return true if both arrays are equal or false otherwise
-     */
-    public static boolean compareEqual(Object[] array1, Object[] array2)
-    {   // Compare Length
-        int len1 = (array1!=null ? array1.length : 0);
-        int len2 = (array2!=null ? array2.length : 0);
-        if (len1!= len2)
-            return false;
-        // Compare Key Values
-        for (int i = 0; i < len1; i++)
-        {   // Check String Values
-            if (!ObjectUtils.compareEqual(array1[i], array2[i]))
-                return false;
-        }
-        return true;
-    }
-    
-    /**
-     * Compares two ColumnExpr for equality
-     *
-     * @param expr a column expression
-     * @param other a column expression
-     *
-     * @return true if both expressions are equal or false otherwise
-     */
-    public static boolean compareEqual(ColumnExpr expr, ColumnExpr other)
-    {
-        if (isWrapper(other) && !isWrapper(expr))
-            return expr.equals(unwrap(other));
-        else  if (!isWrapper(other) && isWrapper(expr))
-            return unwrap(expr).equals(other);
-        // both wrapped or both unwrapped
-        return expr.equals(other);
-    }
     
     /**
      * Compares two objects for equality 
@@ -311,7 +210,7 @@ public final class ObjectUtils
      * @return true if both objects are equal or false otherwise
      */
     @SuppressWarnings("unchecked")
-    public static int compare(Object o1, Object o2)
+    public int compare(Object o1, Object o2)
     {
         // simple case
         if (o1==o2)
@@ -351,27 +250,15 @@ public final class ObjectUtils
         // Compare Strings
         return o1.toString().compareTo(o2.toString());
     }
-    
-    /**
-     * Checks whether a preferred value is valid and returns an alternative 
value if not.
-     * @param <T> the type of the values
-     * @param preferred the preferred return value
-     * @param alternative the alternative return value used if the preferred 
value is null 
-     * @return the preferred value if it is not null or the alternative value 
otherwise
-     */
-    public static <T> T coalesce(T preferred, T alternative)
-    {
-        return (preferred!=null ? preferred : alternative);
-    }
 
     /**
      * converts an object to an integer. If conversion is not possible, an 
error is thrown
      * @param v the value to convert
      * @return the integer value
      */
-    public static int toInteger(Object v)
+    public int toInteger(Object v)
     {
-        if (ObjectUtils.isEmpty(v))
+        if (isEmpty(v))
             return 0;
         if (v instanceof Number)
             return ((Number)v).intValue();
@@ -379,49 +266,15 @@ public final class ObjectUtils
         String str = v.toString();
         return Integer.parseInt(str);
     }
-    
-    /**
-     * Converts an object value to an integer.
-     * <P>
-     * If the object value supplied is null or if conversion is not possible 
then the default value is returned.
-     * @param v the obect to convert
-     * @param defValue the default value if o is null or conversion is not 
possible 
-     * @return the Integer value of o or a default value
-     */
-    public static int getInteger(Object v, int defValue)
-    {
-        // Check empty
-        if (ObjectUtils.isEmpty(v))
-            return defValue;
-        try
-        {   // Try to convert
-            return toInteger(v);
-        } catch (NumberFormatException e) {
-               log.error(String.format("Cannot convert value [%s] to int", v));
-            return defValue;
-        }
-    }
-    
-    /**
-     * Converts an object value to an integer.
-     * <P>
-     * If the object value supplied is null or if conversion is not possible 
then 0 is returned.
-     * @param v the object value to convert
-     * @return the Integer value of o or 0
-     */
-    public static int getInteger(Object v)
-    {
-        return getInteger(v, 0); 
-    }
 
     /**
      * converts an object to a long. If conversion is not possible, an error 
is thrown
      * @param v the value to convert
      * @return the long value
      */
-    public static long toLong(Object v)
+    public long toLong(Object v)
     {
-        if (ObjectUtils.isEmpty(v))
+        if (isEmpty(v))
             return 0;
         if (v instanceof Number)
             return ((Number)v).longValue();
@@ -429,50 +282,16 @@ public final class ObjectUtils
         String str = v.toString();
         return Long.parseLong(str);
     }
-    
-    /**
-     * Converts an object value to a long.
-     * <P>
-     * If the object value supplied is null or if conversion is not possible 
then the default value is returned.
-     * @param v the obect to convert
-     * @param defValue the default value if o is null or conversion is not 
possible 
-     * @return the Integer value of o or a default value
-     */
-    public static long getLong(Object v, long defValue)
-    {
-        // Check empty
-        if (ObjectUtils.isEmpty(v))
-            return defValue;
-        try
-        {   // Try to convert
-            return toLong(v);
-        } catch (NumberFormatException e) {
-               log.error(String.format("Cannot convert value [%s] to long", 
v));
-            return defValue;
-        }
-    }
-    
-    /**
-     * Converts an object value to a long.
-     * <P>
-     * If the object value supplied is null or if conversion is not possible 
then 0 is returned.
-     * @param v the object value to convert
-     * @return the Long value of o or 0
-     */
-    public static long getLong(Object v)
-    {
-        return getLong(v, 0); 
-    }
 
     /**
      * converts an object to a double. If conversion is not possible, an error 
is thrown
      * @param v the value to convert
      * @return the double value
      */
-    public static double toDouble(Object v)
+    public double toDouble(Object v)
     {
         // Get Double value
-        if (ObjectUtils.isEmpty(v))
+        if (isEmpty(v))
             return 0.0;
         if (v instanceof Number)
             return ((Number)v).doubleValue();
@@ -480,50 +299,16 @@ public final class ObjectUtils
         String val = v.toString(); 
         return Double.parseDouble(val);
     }
-    
-    /**
-     * Converts an object value to a double.
-     * <P>
-     * If the object value supplied is null or if conversion is not possible 
then defValue is returned.
-     * @param v the object value to convert
-     * @param defValue the default value
-     * @return the Long value of o or defValue
-     */
-    public static double getDouble(Object v, double defValue)
-    {
-        // Check empty
-        if (ObjectUtils.isEmpty(v))
-            return defValue;
-        try
-        {   // Try to convert
-            return toDouble(v);
-        } catch (NumberFormatException e) {
-            log.error(String.format("Cannot convert value [%s] to double", v));
-            return defValue;
-        }
-    }
-
-    /**
-     * Converts an object value to a double.
-     * <P>
-     * If the object value supplied is null or if conversion is not possible 
then 0.0 is returned.
-     * @param v the object value to convert
-     * @return the Long value of o or 0
-     */
-    public static double getDouble(Object v)
-    {
-        return getDouble(v, 0.0);
-    }
 
     /**
      * converts an object to a decimal. If conversion is not possible, an 
error is thrown
      * @param v the value to convert
      * @return the decimal value
      */
-    public static BigDecimal toDecimal(Object v)
+    public BigDecimal toDecimal(Object v)
     {
         // Get Double value
-        if (ObjectUtils.isEmpty(v))
+        if (isEmpty(v))
             return null;
         if (v instanceof BigDecimal)
             return ((BigDecimal)v);
@@ -544,40 +329,6 @@ public final class ObjectUtils
         return new BigDecimal(v.toString());
     }
     
-    /**
-     * Converts an object value to a BigDecimal.
-     * <P>
-     * If the object value supplied is null or if conversion is not possible 
then defValue is returned.
-     * @param v the object value to convert
-     * @param defValue the default value
-     * @return the BigDecimal value of v or defValue
-     */
-    public static BigDecimal getDecimal(Object v, BigDecimal defValue)
-    {
-        // Check empty
-        if (ObjectUtils.isEmpty(v))
-            return defValue;
-        try
-        {   // Try to convert
-            return toDecimal(v);
-        } catch (NumberFormatException e) {
-            log.error(String.format("Cannot convert value [%s] to BigDecimal", 
v));
-            return defValue;
-        }
-    }
-
-    /**
-     * Converts an object value to a BigDecimal.
-     * <P>
-     * If the object value supplied is null or if conversion is not possible 
then 0.0 is returned.
-     * @param v the object value to convert
-     * @return the Long value of o or 0
-     */
-    public static BigDecimal getDecimal(Object v)
-    {
-        return getDecimal(v, BigDecimal.ZERO);
-    }
-    
     /**
      * Converts an object value to a boolean.
      * <P>
@@ -588,10 +339,10 @@ public final class ObjectUtils
      * @param defValue the default value
      * @return the boolean value or defValue if v is null or empty
      */
-    public static boolean getBoolean(Object v, boolean defValue)
+    public boolean getBoolean(Object v, boolean defValue)
     {
         // Get Boolean value
-        if (ObjectUtils.isEmpty(v))
+        if (isEmpty(v))
             return defValue;
         if (v instanceof Boolean)
             return ((Boolean)v).booleanValue();
@@ -607,17 +358,6 @@ public final class ObjectUtils
         return defValue;
     }
     
-    /**
-     * Converts an object value to a boolean.
-     * see getBoolean(Object v, boolean defValue) for details.
-     * @param v the object to convert
-     * @return the boolean value or false if v is null or empty
-     */
-    public static boolean getBoolean(Object v)
-    {
-        return getBoolean(v, false);
-    }
-    
     /**
      * Converts an object to an enum of the given type
      * @param <T> the type of the enum
@@ -626,7 +366,7 @@ public final class ObjectUtils
      * @return the enum
      */
     @SuppressWarnings("unchecked")
-    public static <T extends Enum<?>> T getEnum(Class<T> enumType, Object 
value)
+    public <T extends Enum<?>> T getEnum(Class<T> enumType, Object value)
     {   // check for null
         if (isEmpty(value))
             return null;
@@ -646,7 +386,7 @@ public final class ObjectUtils
             for (T e : items)
             {
                 Object eVal = ((EnumValue)e).toValue(numeric);
-                if (ObjectUtils.compareEqual(eVal, value))
+                if (compareEqual(eVal, value))
                     return e;
             }
             // error: not found
@@ -680,7 +420,7 @@ public final class ObjectUtils
      * @param name the enum name
      * @return the enum
      */
-    public static <T extends Enum<?>> T getEnumByName(Class<T> enumType, 
String name)
+    public <T extends Enum<?>> T getEnumByName(Class<T> enumType, String name)
     {   // check for null
         if (isEmpty(name))
             return null;
@@ -699,7 +439,7 @@ public final class ObjectUtils
      * @param isNumeric flag if number or string is required
      * @return the number or string representing this enum
      */
-    public static Object getEnumValue(Enum<?> enumValue, boolean isNumeric)
+    public Object getEnumValue(Enum<?> enumValue, boolean isNumeric)
     {
         // convert
         if (enumValue instanceof EnumValue)
@@ -713,13 +453,13 @@ public final class ObjectUtils
      * @param enumValue the enum
      * @return the corresponding string value
      */
-    public static String getString(Enum<?> enumValue)
+    public String getString(Enum<?> enumValue)
     {
         // convert
         if (enumValue instanceof EnumValue)
             return StringUtils.toString(((EnumValue)enumValue).toValue(false));
         /* special case */
-        if (enumValue==null || enumValue.name().equals(NULL))
+        if (enumValue==null || enumValue.name().equals(StringUtils.NULL))
             return null;
         /* use name */
         return enumValue.name();
@@ -730,13 +470,13 @@ public final class ObjectUtils
      * @param value the value to convert
      * @return the corresponding string value
      */
-    public static String getString(Object value)
+    public String getString(Object value)
     {
         if (value==null)
             return null;
         if (value instanceof String)
             return (String)value;
-        if (value==NO_VALUE)
+        if (value==ObjectUtils.NO_VALUE)
             throw new InvalidValueException(value);
         // convert
         if (value instanceof Enum<?>)
@@ -747,6 +487,21 @@ public final class ObjectUtils
         return value.toString();
     }
     
+    /**
+     * returns the string length of an object
+     * @param o the object to check
+     * @return the string length of the object
+     */
+    public int lengthOf(Object o)
+    {
+        if (o==null || o==ObjectUtils.NO_VALUE)
+            return 0;
+        if ((o instanceof String))
+            return ((String)o).length();
+        // convert
+        return o.toString().length();
+    }
+    
     /**
      * Converts an object value to a Date.
      * <P>
@@ -754,11 +509,11 @@ public final class ObjectUtils
      * @return the Date value of o or null
      * @throws ParseException
      */
-    public static Date toDate(Object v)
+    public Date toDate(Object v)
         throws ParseException
     {
         // Get DateTime value
-        if (ObjectUtils.isEmpty(v))
+        if (isEmpty(v))
             return null;
         if (v instanceof java.util.Date)
             return ((java.util.Date)v);
@@ -782,10 +537,10 @@ public final class ObjectUtils
      * @param locale the locale used for conversion
      * @return the Date value of o or null
      */
-    public static Date getDate(Object v, Locale locale)
+    public Date getDate(Object v, Locale locale)
     {
         // Get DateTime value
-        if (ObjectUtils.isEmpty(v))
+        if (isEmpty(v))
             return null;
         if (v instanceof Date)
             return ((Date)v);
@@ -821,10 +576,10 @@ public final class ObjectUtils
      * @param v the object to convert
      * @return the Date value of o or null
      */
-    public static Date getDate(Object v)
+    public Date getDate(Object v)
     {
         // Get DateTime value
-        if (ObjectUtils.isEmpty(v))
+        if (isEmpty(v))
             return null;
         if (v instanceof java.util.Date)
             return ((java.util.Date)v);
@@ -851,10 +606,10 @@ public final class ObjectUtils
      * @param v the object to convert
      * @return the Date value of o or null
      */
-    public static LocalDate getLocalDate(Object v)
+    public LocalDate getLocalDate(Object v)
     {
         // Get DateTime value
-        if (ObjectUtils.isEmpty(v))
+        if (isEmpty(v))
             return null;
         if (v instanceof java.time.LocalDate)
             return (LocalDate)v;
@@ -883,10 +638,10 @@ public final class ObjectUtils
      * @param v the object to convert
      * @return the Date value of o or null
      */
-    public static LocalDateTime getLocalDateTime(Object v)
+    public LocalDateTime getLocalDateTime(Object v)
     {
         // Get DateTime value
-        if (ObjectUtils.isEmpty(v))
+        if (isEmpty(v))
             return null;
         if (v instanceof java.time.LocalDate)
             return ((LocalDate)v).atStartOfDay();
@@ -917,34 +672,35 @@ public final class ObjectUtils
      * @param withTime indicates whether the date string should include the 
time or not
      * @return the date string
      */
-    public static String formatDate(Date date, boolean withTime)
+    public String formatDate(Date date, boolean withTime)
     {
         if (date==null)
             return null;
-       if (withTime)
-               return dateTimeFormatter.get().format(date);
-       else
-               return dateOnlyFormatter.get().format(date);
+        if (withTime)
+            return dateTimeFormatter.get().format(date);
+        else
+            return dateOnlyFormatter.get().format(date);
     }
     
     /**
      * Generic conversion function that will convert a object to another value 
type.
+     * This function is intended to be used for converting values coming from 
the database
+     * to be used by the program
      * 
-     * @param <T> the type to convert to
      * @param c the class type to convert to
-     * @param v the object to convert
+     * @param v the value to convert
      * 
-     * @return the Date value of o or null
+     * @return the converted value
      * 
      * @throws ClassCastException if the object is not null and is not 
assignable to the type T.
      */
     @SuppressWarnings("unchecked")
-    public static <T> T convert(Class<T> c, Object v)
+    public <T> T convert(Class<T> c, Object v)
         throws ClassCastException
     {
         if (v==null || c.isInstance(v))
             return (T)v;
-        if (v==NO_VALUE)
+        if (v==ObjectUtils.NO_VALUE)
             throw new InvalidValueException(v);
         // Get Class form Primitive Type
         if (c.isPrimitive())
@@ -958,267 +714,66 @@ public final class ObjectUtils
             return (T)ev;
         }
         if (c.isAssignableFrom(Boolean.class))
-            return c.cast(getBoolean(v));
+            return c.cast(getBoolean(v, false));
         if (c.isAssignableFrom(Integer.class))
-            return c.cast(getInteger(v));
+            return c.cast(isEmpty(v) ? 0 : toInteger(v));
         if (c.isAssignableFrom(Long.class))
-            return c.cast(getLong(v));
+            return c.cast(isEmpty(v) ? 0 : toLong(v));
         if(c.isAssignableFrom(Double.class))
-               return c.cast(getDouble(v));
+            return c.cast(isEmpty(v) ? 0.0f : toDouble(v));
         if(c.isAssignableFrom(BigDecimal.class))
-            return c.cast(getDecimal(v));
+            return c.cast(isEmpty(v) ? BigDecimal.ZERO : toDecimal(v));
         if (c.isAssignableFrom(String.class))
-            return c.cast(v.toString());
+            return c.cast(getString(v));
         // other
         return c.cast(v);
     }
 
     /**
-     * Checks if a class is assignment compatible with another class
-     * @param target the target class
-     * @param source the source class
-     * @return true if assignment compatible or false otherwise
-     */
-    public static boolean isAssignmentCompatible(Class<?> target, Class<?> 
source)
-    {
-        // try plain assignment
-        if (target.isAssignableFrom(source))
-            return true;
-        // Get Class form Primitive Type
-        if (source.isPrimitive())
-        {   // Get's the Java Class representing the primitive type
-            source = MethodUtils.getPrimitiveWrapper(source);
-            if (source == null)
-                return false;
-            if (target.isAssignableFrom(source))
-                return true;
-        }
-        // Get Class form Primitive Type
-        if (target.isPrimitive())
-        {   // Get's the Java Class representing the primitive type
-            target = MethodUtils.getPrimitiveWrapper(target);
-            if (target == null)
-                return false;
-            if (target.isAssignableFrom(source))
-                return true;
-        }
-        // Assume all numeric types can be converted to target class
-        Class<Number> numberClass = Number.class;
-        if (numberClass.isAssignableFrom(target) &&
-            numberClass.isAssignableFrom(source))
-        {   // Both are numeric
-            return true;
-        }
-        // Special case: Allow character to string assignment
-        if (source==Character.class && target==String.class)
-        {
-            return true;
-        }    
-        // Not compatible
-        return false;
-    }
-    
-    /**
-     * Generic conversion function that will convert a list to another list 
type.
-     * 
-     * @param <T> the type of elements
-     * @param t the type class
-     * @param source the source collection
-     * 
-     * @return the new list type
-     */
-    public static <T> List<T> convert(Class<T> t, Collection<? extends T> 
source)
-    {
-        if (source==null)
-            return null;
-        List<T> target = new ArrayList<T>(source.size());
-        target.addAll(source);
-        return target;
-    }
-    
-    /**
-     * Converts varArgs to an array
-     * 
-     * @param <T> the type of elements
-     * @param t the type of the array
-     * @param values the array values
-     * 
-     * @return the array
-     */
-    @SafeVarargs
-    public static <T> T[] toArray(Class<T> t, T... values)
-    {
-        if (values.length==0)
-            throw new InvalidArgumentException("values", values);
-        return values;
-    }
-    
-    /**
-     * Converts an array to a list
-     * 
-     * @param <T> the type of elements
-     * @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 
-     * @return the String array
+     * Converts a value to a specific DataType
+     * The returned value is used for generating SQL statements
+     * @param dataType the target data type
+     * @param value the value to convert
+     * @return the value to be used in SQL statements
      */
-    public static String[] toStringArray(Object[] objArray, String defValue)
+    public Object convertValue(DataType dataType, Object value)
     {
-        if (objArray==null)
+        // check null
+        if (value == null)
             return null;
-        String[] strArray = new String[objArray.length];
-        for (int i=0; i<objArray.length; i++)
-        {
-            if (objArray[i]!=null)
-                strArray[i]=objArray[i].toString();
-            else 
-                strArray[i]=defValue;
-        }
-        return strArray;
-    }
-
-    /**
-     * Checks whether a object implements the Unwrappable interface and is 
also a wrapper
-     * If the object does not Implement the Interface or is not a wrapper then 
false is returned 
-     * @param object the object to check
-     * @return true if the object is a wrapper or false otherwise
-     */
-    public static boolean isWrapper(Object object)
-    {
-        return ((object instanceof Unwrappable<?>)) && 
((Unwrappable<?>)object).isWrapper();
-    }
-
-    /**
-     * Unwraps an object implementing the Unwrappable interface
-     * If the object does not Implement the Interface or is not a wrapper then 
the object itself is returned 
-     * @param <T> the type of the object
-     * @param object the object to unwrap
-     * @return the unwrapped object or the object itself
-     */
-    @SuppressWarnings("unchecked")
-    public static <T> T unwrap(T object)
-    {
-        if ((object instanceof Unwrappable<?>) && 
((Unwrappable<?>)object).isWrapper())
-        {   // recursive
-            return unwrap(((Unwrappable<T>)object).unwrap());
-        }
-        return object;
-    }
-    
-    /**
-     * returns whether or not a array contains a certain item
-     * performs a quick (==) comparison first
-     * if not found a second check is made using equals and unwrapping of 
items 
-     * 
-     * @param <T> the type of the object
-     * @param array the array to search
-     * @param item the item to search for
-     * 
-     * @return true if the array contains the item or false otherwise
-     */
-    @SuppressWarnings("unchecked")
-    public static <T> int indexOf(T[] array, T item)
-    {
-        if (array==null || array.length==0)
-            return -1;
-        // 1st try (quick)
-        for (int i=0; i<array.length; i++)
-        {
-            if (array[i]==item)
-                return i;
+        // Strings special
+        if ((value instanceof String) && ((String)value).length()==0)
+            value = null;
+        // check for enum
+        if (value instanceof Enum<?>)
+        {   // convert enum
+            value = getEnumValue((Enum<?>)value, dataType.isNumeric());
         }
-        // 2nd try (equals)
-        for (int i=0; i<array.length; i++)
-        {
-            T ai = array[i];
-            if (ai!=null && ai.equals(item))                
-                return i;
+        // check option entry
+        else if (value instanceof OptionEntry)
+        {   // option value
+            value = ((OptionEntry)value).getValue();
         }
-        // 3rd try (unwrap)
-        for (int i=0; i<array.length; i++)
+        // check type
+        switch (dataType)
         {
-            T ai = array[i];
-            // check wrapper
-            if ((ai instanceof Unwrappable) && 
((Unwrappable<?>)ai).isWrapper())
-            {   // unwrap
-                Object unwrapped = ((Unwrappable<?>)ai).unwrap();
-                if (unwrapped==item || unwrapped.equals(item))
-                    return i;
-            }
-        }
-        // 3rd try (unwrap)
-        if ((item instanceof Unwrappable) && 
((Unwrappable<?>)item).isWrapper())
-        {   // unwrap
-            return indexOf(array, ((Unwrappable<T>)item).unwrap());
+            case BLOB:
+                return value; // unchanged
+            case BOOL:
+                return getBoolean(value, false);
+            case INTEGER:
+                return (value instanceof Number) ? value : toLong(value);
+            case FLOAT:
+                return (value instanceof Number) ? value : toDouble(value);
+            case DECIMAL:
+                return (value instanceof Number) ? value : toDecimal(value);
+            case CHAR:
+            case CLOB:
+            case VARCHAR:                
+                return (value instanceof String) ? value : value.toString(); 
// not not call getString(...);
+            default:
+                // use as is
+                return value;
         }
-        // not found
-        return -1;
-    }
-    
-    /**
-     * returns whether or not a array contains a certain item
-     * performs a simple (==) comparison (fast)
-     * 
-     * @param <T> the type of elements
-     * @param array the array to search
-     * @param item the item to search for
-     * 
-     * @return true if the array contains the item or false otherwise
-     */
-    public static <T> boolean contains(T[] array, T item)
-    {
-        return (indexOf(array, item)>=0);
-    }
-
-    /**
-     * combines two arrays
-     * @param <T> the type of the array items
-     * @param left the left array
-     * @param right the right array
-     * @return the combined array
-     */
-    public static <T> T[] combine(T[] left, T[] right)
-    {
-        if (left==null || left.length==0)
-            return right;
-        if (right==null || right.length==0)
-            return left;
-        // combine both
-        T[] result = Arrays.copyOf(left, left.length + right.length);
-        System.arraycopy(right, 0, result, left.length, right.length);
-        return result;
-    }
-
-    /**
-     * appends an element to an array
-     * @param <T> the type of the array items
-     * @param array the array
-     * @param element the new element
-     * @return the combined array
-     */
-    public static <T> T[] append(T[] array, T element)
-    {
-        if (array==null)
-            throw new InvalidArgumentException("array", array);
-        // append element
-        T[] result = Arrays.copyOf(array, array.length + 1);
-        result[array.length] = element;
-        return result;
     }
 }
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBCmdParam.java 
b/empire-db/src/main/java/org/apache/empire/db/DBCmdParam.java
index 94f0225f..f532e203 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBCmdParam.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBCmdParam.java
@@ -57,15 +57,11 @@ public class DBCmdParam extends DBExpr
      */
     protected Object getCmdParamValue(Object value)
     {
-        // check null
-        if (value == null)
-            return null;
-        // check for enum
-        if (value instanceof Enum<?>)
-        {   // convert enum
-            return ObjectUtils.getEnumValue((Enum<?>)value, type.isNumeric());
-        }
-        // check type
+        if (value!=null)
+            value = ObjectUtils.convertValue(type, value);
+        if (value==null)
+            return value;
+        // Check CLOB and BLOB
         switch (type)
         {
             case BLOB:
@@ -80,19 +76,8 @@ public class DBCmdParam extends DBExpr
                     return value;
                 // create a clob data
                 return new DBClobData(value.toString());
-            case BOOL:
-               return ObjectUtils.getBoolean(value);
-            case INTEGER:
-                return (value instanceof Number) ? value : 
ObjectUtils.toLong(value);
-            case FLOAT:
-                return (value instanceof Number) ? value : 
ObjectUtils.toDouble(value);
-            case DECIMAL:
-                return (value instanceof Number) ? value : 
ObjectUtils.toDecimal(value);
-            case CHAR:
-            case VARCHAR:
-                return (value instanceof String) ? value : value.toString();
             default:
-                // use as is
+                // the value
                 return value;
         }
     }
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBRecordBase.java 
b/empire-db/src/main/java/org/apache/empire/db/DBRecordBase.java
index 9b8be573..02c548ce 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBRecordBase.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBRecordBase.java
@@ -656,23 +656,15 @@ public abstract class DBRecordBase extends DBRecordData 
implements Record, Clone
             setParentRecord(getColumn(index), (DBRecordBase)value);
             return;
         }
-        // Strings special
-        if ((value instanceof String) && ((String)value).length()==0)
-            value = null;
         // Is value valid
         Object current = fields[index]; 
         if (current==ObjectUtils.NO_VALUE)
             throw new FieldValueNotFetchedException(getColumn(index));
         // convert
         DBColumn column = getColumn(index);
-        // must convert enums
-        if (value instanceof Enum<?>)
-        {   // convert enum
-            Enum<?> enumVal = ((Enum<?>)value);
-            boolean numeric = column.getDataType().isNumeric();
-            value = ObjectUtils.getEnumValue(enumVal, numeric);
-        }
         // Has Value changed?
+        if (value!= null)
+            value = ObjectUtils.convertValue(column.getDataType(), value);
         if (ObjectUtils.compareEqual(current, value))
         {   // value has not changed!
             return; 
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 b29511ad..564c730c 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
@@ -1088,8 +1088,6 @@ public abstract class DBRowSet extends DBExpr implements 
EntityType
                 {      // Update a field
                     if (col.isReadOnly())
                         log.warn("updateRecord: Read-only column '" + 
col.getName() + " has been modified!");
-                    // *** unnecessary check removed 2.5.0 ***
-                    // col.validate(value);  
                     // Set the column
                     cmd.set(col.to(value));
                     setCount++;
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBSQLBuilder.java 
b/empire-db/src/main/java/org/apache/empire/db/DBSQLBuilder.java
index 3b689f87..8c83aefb 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBSQLBuilder.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBSQLBuilder.java
@@ -27,7 +27,6 @@ import java.util.Collection;
 import java.util.Date;
 
 import org.apache.empire.commons.ObjectUtils;
-import org.apache.empire.commons.OptionEntry;
 import org.apache.empire.commons.StringUtils;
 import org.apache.empire.data.DataType;
 import org.apache.empire.dbms.DBMSHandler;
@@ -186,18 +185,9 @@ public abstract class DBSQLBuilder implements Appendable
         {   // it's an expression
             ((DBExpr) value).addSQL(this, context);
             return;
-        } 
-        // check option entry
-        if (value instanceof OptionEntry)
-        {   // option value
-            value = ((OptionEntry)value).getValue();
-        }
-        // check enum
-        if (value instanceof Enum<?>)
-        {   // check enum
-            value = ObjectUtils.getEnumValue((Enum<?>)value, 
dataType.isNumeric());
         }
-        else if (value instanceof Collection<?>)
+        // Check colletion
+        if (value instanceof Collection<?>)
         {   // collection 2 array
             value = ((Collection<?>)value).toArray();
         }
@@ -215,7 +205,10 @@ public abstract class DBSQLBuilder implements Appendable
             return;
         } 
         else
-        {   // Get Value Expression from dmbs
+        {   // Convert to database format
+            if (value!= null)
+                value = ObjectUtils.convertValue(dataType, value);
+            // append now
             appendSimpleValue(dataType, value);
         }
     }

Reply via email to