You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@empire-db.apache.org by do...@apache.org on 2019/11/22 10:49:30 UTC

[empire-db] branch master updated: EMPIREDB-304 improved enum type support

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 0beefec  EMPIREDB-304 improved enum type support
0beefec is described below

commit 0beefec77d107c041fc006eaa15fe8acf61e016b
Author: Rainer Döbele <do...@apache.org>
AuthorDate: Fri Nov 22 11:49:26 2019 +0100

    EMPIREDB-304
    improved enum type support
---
 .../empire/jsf2/controls/RadioInputControl.java    | 30 +------
 .../empire/jsf2/controls/SelectInputControl.java   | 43 ++--------
 .../empire/jsf2/utils/TagEncodingHelper.java       |  6 ++
 .../org/apache/empire/commons/ObjectUtils.java     | 43 ++++++++++
 .../main/java/org/apache/empire/data/Column.java   |  9 ++-
 .../org/apache/empire/data/bean/BeanProperty.java  | 14 +++-
 .../main/java/org/apache/empire/db/DBColumn.java   | 14 +++-
 .../main/java/org/apache/empire/db/DBRecord.java   | 21 +++--
 .../java/org/apache/empire/db/DBRecordData.java    | 91 +++++++++-------------
 .../java/org/apache/empire/db/DBTableColumn.java   | 10 ++-
 10 files changed, 151 insertions(+), 130 deletions(-)

diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/RadioInputControl.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/RadioInputControl.java
index 334ae22..b43fbdc 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/RadioInputControl.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/RadioInputControl.java
@@ -19,7 +19,6 @@
 package org.apache.empire.jsf2.controls;
 
 import java.io.IOException;
-import java.lang.reflect.Field;
 import java.util.Iterator;
 import java.util.List;
 
@@ -35,9 +34,7 @@ import org.apache.empire.commons.ObjectUtils;
 import org.apache.empire.commons.OptionEntry;
 import org.apache.empire.commons.Options;
 import org.apache.empire.data.Column;
-import org.apache.empire.exceptions.InternalException;
 import org.apache.empire.exceptions.InvalidArgumentException;
-import org.apache.empire.exceptions.ItemNotFoundException;
 import org.apache.empire.exceptions.UnexpectedReturnValueException;
 import org.apache.empire.jsf2.app.TextResolver;
 import org.slf4j.Logger;
@@ -329,30 +326,9 @@ public class RadioInputControl extends InputControl
     @Override
     protected Object parseInputValue(String value, InputInfo ii)
     {
-        Object enumType = ii.getColumn().getAttribute(Column.COLATTR_ENUMTYPE);
-        if (enumType != null)
-        {   try
-            { // get enum
-                Class<?> enumClass = (Class<?>) enumType;
-                Field field = enumClass.getDeclaredField(value);
-                return field.get(null);
-            }
-            catch (NoSuchFieldException e)
-            {
-                throw new ItemNotFoundException(value);
-            }
-            catch (SecurityException e)
-            {
-                throw new InternalException(e);
-            }
-            catch (IllegalArgumentException e)
-            {
-                throw new InternalException(e);
-            }
-            catch (IllegalAccessException e)
-            {
-                throw new InternalException(e);
-            }
+        if (ii.getColumn().isEnum())
+        {   // convert to enum
+            return ObjectUtils.getEnum(ii.getColumn().getEnumType(), value);
         }
         return value;
     }
diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/SelectInputControl.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/SelectInputControl.java
index 70fae41..91a89e1 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/SelectInputControl.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/SelectInputControl.java
@@ -325,17 +325,10 @@ public class SelectInputControl extends InputControl
     {
         if ((value instanceof Number)) 
         {   // Check whether it's an Enum
-            Object enumType = ii.getColumn().getAttribute(Column.COLATTR_ENUMTYPE);
-            if ((enumType instanceof Class<?>)) 
-            {   // Convert ordinal value to Enum
-                int ordinal = ObjectUtils.getInteger(value);
-                @SuppressWarnings("unchecked")
-                Class<? extends Enum<?>> enumTypeClazz = (Class<? extends Enum<?>>)enumType;
-                Enum<?>[] items = enumTypeClazz.getEnumConstants();
-                if (ordinal>=0 && ordinal<items.length)
-                    value = items[ordinal].name();
-                else
-                    log.warn("Enum lookup failed. Ordinal {} out of range.", ordinal);
+            if (ii.getColumn().isEnum()) 
+            {   // Convert ordinal value to Enum-name
+                Enum<?> enumVal = ObjectUtils.getEnum(ii.getColumn().getEnumType(), value);
+                value = enumVal.name();
             } 
         }
         // the value
@@ -356,31 +349,9 @@ public class SelectInputControl extends InputControl
     @Override
     protected Object parseInputValue(String value, InputInfo ii)
     {
-        Object enumType = ii.getColumn().getAttribute(Column.COLATTR_ENUMTYPE);
-        if (enumType != null)
-        {
-            try
-            { // get enum
-                Class<?> enumClass = (Class<?>) enumType;
-                Field field = enumClass.getDeclaredField(value);
-                return field.get(null);
-            }
-            catch (NoSuchFieldException e)
-            {
-                throw new ItemNotFoundException(value);
-            }
-            catch (SecurityException e)
-            {
-                throw new InternalException(e);
-            }
-            catch (IllegalArgumentException e)
-            {
-                throw new InternalException(e);
-            }
-            catch (IllegalAccessException e)
-            {
-                throw new InternalException(e);
-            }
+        if (ii.getColumn().isEnum())
+        {   // convert to enum
+            return ObjectUtils.getEnum(ii.getColumn().getEnumType(), value);
         }
         return value;
     }
diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/TagEncodingHelper.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/TagEncodingHelper.java
index c28bb2e..a8b6429 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/TagEncodingHelper.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/TagEncodingHelper.java
@@ -176,6 +176,12 @@ public class TagEncodingHelper implements NamingContainer
         }
 
         @Override
+        public Class<Enum<?>> getEnumType()
+        {
+            return getSourceColumn().getEnumType();
+        }
+
+        @Override
         public Object validate(Object value)
         {
             log.warn("validate not supported for {}", expr.getName());
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 8a6a3c8..8ce8f1a 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
@@ -35,6 +35,7 @@ import org.apache.commons.beanutils.MethodUtils;
 import org.apache.empire.exceptions.EmpireException;
 import org.apache.empire.exceptions.InternalException;
 import org.apache.empire.exceptions.InvalidArgumentException;
+import org.apache.empire.exceptions.ItemNotFoundException;
 import org.apache.empire.exceptions.NotSupportedException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -445,6 +446,48 @@ public final class ObjectUtils
     }
     
     /**
+     * Converts an object to an enum of the given type
+     * @param enumType the enum type
+     * @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
+        T[] items = enumType.getEnumConstants();
+        if (value instanceof Number)
+        {   // 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);
+        }
+    }
+    
+    /**
      * Converts an object value to a Date.
      * <P>
      * If the object value supplied is null or if conversion is not possible then null is returned.
diff --git a/empire-db/src/main/java/org/apache/empire/data/Column.java b/empire-db/src/main/java/org/apache/empire/data/Column.java
index 622ac01..58e6e0d 100644
--- a/empire-db/src/main/java/org/apache/empire/data/Column.java
+++ b/empire-db/src/main/java/org/apache/empire/data/Column.java
@@ -83,11 +83,18 @@ public interface Column extends ColumnExpr
     /**
      * Returns true if an enum type has been set for this column
      * <P>
-     * @return eturns true if an enum type has been set for this column
+     * @return true if an enum type has been set for this column
      */
     boolean isEnum();
 
     /**
+     * Returns the enum type for this column
+     * <P>
+     * @return the enum type
+     */
+    Class<Enum<?>> getEnumType();
+
+    /**
      * Checks if the given value is a valid value for this column 
      * If not, an exception is thrown
      * @return the value the validated and possibly converted value
diff --git a/empire-db/src/main/java/org/apache/empire/data/bean/BeanProperty.java b/empire-db/src/main/java/org/apache/empire/data/bean/BeanProperty.java
index 24c7609..ccbac58 100644
--- a/empire-db/src/main/java/org/apache/empire/data/bean/BeanProperty.java
+++ b/empire-db/src/main/java/org/apache/empire/data/bean/BeanProperty.java
@@ -173,7 +173,19 @@ public class BeanProperty implements Column
     @Override
     public boolean isEnum()
     {
-        return (attributes!=null && getAttribute(COLATTR_ENUMTYPE)!=null);
+        return (getEnumType()!=null);
+    }
+
+    /**
+     * Returns the enum type for this column
+     * <P>
+     * @return the enum type
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public Class<Enum<?>> getEnumType()
+    {
+        return (attributes!=null ? (Class<Enum<?>>)getAttribute(COLATTR_ENUMTYPE) : null);
     }
 
     /**
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBColumn.java b/empire-db/src/main/java/org/apache/empire/db/DBColumn.java
index 85f5276..c05632a 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBColumn.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBColumn.java
@@ -392,7 +392,19 @@ public abstract class DBColumn extends DBColumnExpr
     @Override
     public boolean isEnum()
     {
-        return (attributes!=null && getAttribute(COLATTR_ENUMTYPE)!=null);
+        return (getEnumType()!=null);
+    }
+
+    /**
+     * Returns the enum type for this column
+     * <P>
+     * @return the enum type
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public Class<Enum<?>> getEnumType()
+    {
+        return (attributes!=null ? (Class<Enum<?>>)getAttribute(COLATTR_ENUMTYPE) : null);
     }
 
     /**
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBRecord.java b/empire-db/src/main/java/org/apache/empire/db/DBRecord.java
index 407cf73..834cd3c 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBRecord.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBRecord.java
@@ -646,19 +646,30 @@ public class DBRecord extends DBRecordData implements Record, Cloneable
         Object current = fields[index]; 
         if (current==ObjectUtils.NO_VALUE)
             throw new FieldValueNotFetchedException(getColumn(index));
+        // convert
+        DBColumn column = rowset.getColumn(index);
+        // must convert enums
+        if (value!=null && value.getClass().isEnum())
+        {   // convert enum
+            Enum<?> enumVal = ((Enum<?>)value);
+            boolean numeric = column.getDataType().isNumeric();
+            value = (numeric ? enumVal.ordinal() : enumVal.name());
+        }
         // Has Value changed?
         if (ObjectUtils.compareEqual(current, value))
-            return; // no change
-        // Field has changed
-        DBColumn column = rowset.getColumn(index);
+        {   // value has not changed!
+            return; 
+        }
         // Check whether we can change this field
         if (!allowFieldChange(column))
         {   // Read Only column may be set
             throw new FieldIsReadOnlyException(column);
         }
-        // Is Value valid
+        // Is Value valid?
         if (this.validateFieldValues)
-        	value = validateValue(column, value);
+        {   // validate
+            value = validateValue(column, value);
+        }
         // Init original values
         modifyValue(index, value, true);
     }
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBRecordData.java b/empire-db/src/main/java/org/apache/empire/db/DBRecordData.java
index 53dd2e1..f9b8d38 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBRecordData.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBRecordData.java
@@ -31,7 +31,6 @@ import org.apache.empire.data.Column;
 import org.apache.empire.data.ColumnExpr;
 import org.apache.empire.data.RecordData;
 import org.apache.empire.db.exceptions.FieldIllegalValueException;
-import org.apache.empire.db.exceptions.FieldValueOutOfRangeException;
 import org.apache.empire.exceptions.BeanPropertySetException;
 import org.apache.empire.exceptions.InvalidArgumentException;
 import org.apache.empire.exceptions.ItemNotFoundException;
@@ -103,8 +102,8 @@ public abstract class DBRecordData extends DBObject
     public int getInt(int index)
     {
         // Get Integer value
-        Object o = getValue(index);
-        return ObjectUtils.getInteger(o);
+        Object value = getValue(index);
+        return ObjectUtils.getInteger(value);
     }
     
     /**
@@ -129,8 +128,8 @@ public abstract class DBRecordData extends DBObject
     public long getLong(int index)
     {
         // Get Integer value
-        Object o = getValue(index);
-        return ObjectUtils.getLong(o);
+        Object value = getValue(index);
+        return ObjectUtils.getLong(value);
     }
     
     /**
@@ -155,8 +154,8 @@ public abstract class DBRecordData extends DBObject
     public double getDouble(int index)
     {
         // Get Double value
-        Object v = getValue(index);
-        return ObjectUtils.getDouble(v);
+        Object value = getValue(index);
+        return ObjectUtils.getDouble(value);
     }
 
     /**
@@ -181,8 +180,8 @@ public abstract class DBRecordData extends DBObject
     public BigDecimal getDecimal(int index)
     {
         // Get Double value
-        Object v = getValue(index);
-        return ObjectUtils.getDecimal(v);
+        Object value = getValue(index);
+        return ObjectUtils.getDecimal(value);
     }
 
     /**
@@ -207,8 +206,8 @@ public abstract class DBRecordData extends DBObject
     public boolean getBoolean(int index)
     {
         // Get Boolean value
-        Object o = getValue(index);
-        return ObjectUtils.getBoolean(o);
+        Object value = getValue(index);
+        return ObjectUtils.getBoolean(value);
     }
     
     /**
@@ -231,8 +230,8 @@ public abstract class DBRecordData extends DBObject
     public String getString(int index)
     {
         // Get Integer value
-        Object o = getValue(index);
-        return StringUtils.toString(o);
+        Object value = getValue(index);
+        return StringUtils.toString(value);
     }
 
     /**
@@ -257,8 +256,8 @@ public abstract class DBRecordData extends DBObject
     public Date getDateTime(int index)
     {
         // Get DateTime value
-        Object o = getValue(index);
-        return ObjectUtils.getDate(o);
+        Object value = getValue(index);
+        return ObjectUtils.getDate(value);
     }
     
     /**
@@ -283,33 +282,21 @@ public abstract class DBRecordData extends DBObject
      * @return the enum value
      */
     public <T extends Enum<?>> T getEnum(int index, Class<T> enumType)
-    {
-        // check column data type
+    {   // check for null
+        if (isNull(index))
+            return null;
+        // convert
         ColumnExpr col = getColumnExpr(index);
-        boolean numeric = col.getDataType().isNumeric();
-        T[] items = enumType.getEnumConstants();
-        if (numeric)
-        {   // by ordinal
-            if (isNull(index))
-                return null;
-            int ordinal = getInt(index);
-            // check range
-            if (ordinal<0 || ordinal>=items.length)
-                throw new FieldValueOutOfRangeException(col.getSourceColumn(), 0, items.length);
-            // return enum
-            return items[ordinal]; 
-        }
-        else
-        {   // by name
-            String name = getString(index);
-            if (StringUtils.isEmpty(name))
-                return null;
-            // find name
-            for (T e : items)
-                if (e.name().equals(name))
-                    return e;
-            // error: not found
-            throw new FieldIllegalValueException(col.getSourceColumn(), name);
+        try {
+            // Convert to enum, depending on DataType
+            boolean numeric = col.getDataType().isNumeric();
+            return ObjectUtils.getEnum(enumType, (numeric ? getInt(index) : getValue(index)));
+
+        } catch (Exception e) {
+            // Illegal value
+            String value = StringUtils.valueOf(getValue(index));
+            log.error("Unable to resolve enum value of '{}' for type {}", value, enumType.getName());
+            throw new FieldIllegalValueException(col.getSourceColumn(), value, e);
         }
     }
 
@@ -336,8 +323,8 @@ public abstract class DBRecordData extends DBObject
     @SuppressWarnings("unchecked")
     public final <T extends Enum<?>> T getEnum(Column column)
     {
-        Object enumType = column.getAttribute(Column.COLATTR_ENUMTYPE);
-        if (enumType==null || !(enumType instanceof Class<?>))
+        Class<Enum<?>> enumType = column.getEnumType();
+        if (enumType==null)
         {   // Not an enum column (Attribute "enumType" has not been set)
             throw new InvalidArgumentException("column", column);
         }
@@ -371,7 +358,6 @@ public abstract class DBRecordData extends DBObject
     /**
      * Set a single property value of a java bean object used by readProperties.
      */
-    @SuppressWarnings("rawtypes")
     protected void setBeanProperty(ColumnExpr column, Object bean, String property, Object value)
     {
         if (StringUtils.isEmpty(property))
@@ -392,18 +378,11 @@ public abstract class DBRecordData extends DBObject
                 value = DateUtils.addDate((Date)value, 0, 0, 0);
             }
             */
-            Object type = column.getAttribute(Column.COLATTR_ENUMTYPE);
-            if (type!=null && value!=null)
-            {
-                String name = value.toString();
-                @SuppressWarnings("unchecked")
-                Class<Enum> enumType = (Class<Enum>)type;
-                for (Enum e : enumType.getEnumConstants())
-                    if (e.name().equals(name))
-                    {
-                        value = e;
-                        break;
-                    }
+            @SuppressWarnings("unchecked")
+            Class<Enum<?>> enumType = (Class<Enum<?>>)column.getAttribute(Column.COLATTR_ENUMTYPE);
+            if (enumType!=null && value!=null)
+            {   // value to enum
+                value = ObjectUtils.getEnum(enumType, value);
             }
             // Set Property Value
             if (value!=null)
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBTableColumn.java b/empire-db/src/main/java/org/apache/empire/db/DBTableColumn.java
index 53f3716..af494e0 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBTableColumn.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBTableColumn.java
@@ -430,7 +430,7 @@ public class DBTableColumn extends DBColumn
             case DECIMAL:
                 // check enum
                 if (value.getClass().isEnum())
-                {   
+                {   // convert enum   
                     value = ((Enum<?>)value).ordinal();
                 }
                 // check number
@@ -468,7 +468,7 @@ public class DBTableColumn extends DBColumn
             case INTEGER:
                 // check enum
                 if (value.getClass().isEnum())
-                {   
+                {   // convert enum   
                     value = ((Enum<?>)value).ordinal();
                 }
                 // check number
@@ -490,12 +490,16 @@ public class DBTableColumn extends DBColumn
             case TEXT:
             case VARCHAR:
             case CHAR:
+                // check enum
                 if (value.getClass().isEnum())
-                {   // check enum
+                {   // convert enum   
                     value = ((Enum<?>)value).name();
                 }
+                // check length
                 if (value.toString().length() > size)
+                {
                     throw new FieldValueTooLongException(this);
+                }
                 break;
                 
             default: