]> source.dussan.org Git - iciql.git/commitdiff
Support generic types for EnumId mapping
authorJames Moger <james.moger@gitblit.com>
Mon, 6 Oct 2014 16:46:50 +0000 (12:46 -0400)
committerJames Moger <james.moger@gitblit.com>
Thu, 23 Oct 2014 02:29:05 +0000 (22:29 -0400)
releases.moxie
src/main/java/com/iciql/Iciql.java
src/main/java/com/iciql/ModelUtils.java
src/main/java/com/iciql/TableDefinition.java
src/main/java/com/iciql/util/Utils.java
src/test/java/com/iciql/test/EnumsTest.java
src/test/java/com/iciql/test/models/EnumModels.java

index 10bf70f6e1bbbebcc06732c497216de6719ad74a..b81afc4b5ffffc591d600cc3406543f07f5f4153 100644 (file)
@@ -5,7 +5,7 @@ r21: {
     title: ${project.name} ${project.version} released
     id: ${project.version}
     date: ${project.buildDate}
-    note: ~
+    note: "If you are upgrading and using EnumId mapping you will have to update your models to define the target class for the enumid mapping."
     html: ~
     text: ~
     security: ~
@@ -13,11 +13,13 @@ r21: {
     - Return null NPE in selectFirst() if list is empty (pr-5)
     - Fix Moxie toolkit download URL (pr-6)
     - Be more careful with primitive numeric type rollovers
-    changes: ~
+    changes:
+    - Revised EnumId interface to support generic types
     additions:
     - Add syntax for IN and NOT IN (pr-7)
     - Add support for nested AND/OR conditions (pr-8)
     - Add support for mapping SQL BOOLEAN to primitive numeric types, not just object numeric types
+    - Add support for customizing EnumId mapping, you can now map enum constants to values of your choice as long as they are a standard type
     dependencyChanges: 
     - H2 1.4
     - HSQLDB 2.3
index 9f73ffa82f08cbed3bc91d9ab4ae12729ca81582..521e46066e17957a00be89da1c72cf5efa5bd941 100644 (file)
@@ -171,7 +171,7 @@ import java.lang.annotation.Target;
  * <p>\r
  * Automatic model generation: you may automatically generate model classes as\r
  * strings with the Db and DbInspector objects:\r
- * \r
+ *\r
  * <pre>\r
  * Db db = Db.open(&quot;jdbc:h2:mem:&quot;, &quot;sa&quot;, &quot;sa&quot;);\r
  * DbInspector inspector = new DbInspector(db);\r
@@ -179,10 +179,10 @@ import java.lang.annotation.Target;
  *         inspector.generateModel(schema, table, packageName,\r
  *         annotateSchema, trimStrings)\r
  * </pre>\r
- * \r
+ *\r
  * Or you may use the GenerateModels tool to generate and save your classes to\r
  * the file system:\r
- * \r
+ *\r
  * <pre>\r
  * java -jar iciql.jar\r
  *      -url &quot;jdbc:h2:mem:&quot;\r
@@ -190,10 +190,10 @@ import java.lang.annotation.Target;
  *      -package packageName -folder destination\r
  *      -annotateSchema false -trimStrings true\r
  * </pre>\r
- * \r
+ *\r
  * Model validation: you may validate your model class with DbInspector object.\r
  * The DbInspector will report errors, warnings, and suggestions:\r
- * \r
+ *\r
  * <pre>\r
  * Db db = Db.open(&quot;jdbc:h2:mem:&quot;, &quot;sa&quot;, &quot;sa&quot;);\r
  * DbInspector inspector = new DbInspector(db);\r
@@ -208,7 +208,7 @@ public interface Iciql {
        /**\r
         * An annotation for an iciql version.\r
         * <p>\r
-        * \r
+        *\r
         * @IQVersion(1)\r
         */\r
        @Retention(RetentionPolicy.RUNTIME)\r
@@ -229,7 +229,7 @@ public interface Iciql {
        /**\r
         * An annotation for a schema.\r
         * <p>\r
-        * \r
+        *\r
         * @IQSchema("PUBLIC")\r
         */\r
        @Retention(RetentionPolicy.RUNTIME)\r
@@ -278,9 +278,9 @@ public interface Iciql {
                 * <li>com.iciql.iciql.IndexType.HASH\r
                 * <li>com.iciql.iciql.IndexType.UNIQUE_HASH\r
                 * </ul>\r
-                * \r
+                *\r
                 * HASH indexes may only be valid for single column indexes.\r
-                * \r
+                *\r
                 */\r
                IndexType type() default IndexType.STANDARD;\r
 \r
@@ -307,21 +307,21 @@ public interface Iciql {
        public static enum ConstraintUpdateType {\r
                UNSET, CASCADE, RESTRICT, SET_NULL, NO_ACTION, SET_DEFAULT;\r
        }\r
-       \r
+\r
        /**\r
         * Enumeration defining the deferrability.\r
         */\r
        public static enum ConstraintDeferrabilityType {\r
                UNSET, DEFERRABLE_INITIALLY_DEFERRED, DEFERRABLE_INITIALLY_IMMEDIATE, NOT_DEFERRABLE;\r
        }\r
-       \r
+\r
        /**\r
         * A foreign key constraint annotation.\r
         * <p>\r
         * <ul>\r
         * <li>@IQContraintForeignKey(\r
-        *    foreignColumns = { "idaccount"}, \r
-        *    referenceName = "account", \r
+        *    foreignColumns = { "idaccount"},\r
+        *    referenceName = "account",\r
         *    referenceColumns = { "id" },\r
         *    deleteType = ConstrainDeleteType.CASCADE,\r
         *    updateType = ConstraintUpdateType.NO_ACTION )\r
@@ -372,7 +372,7 @@ public interface Iciql {
                 * </ul>\r
                 */\r
                ConstraintDeferrabilityType deferrabilityType() default ConstraintDeferrabilityType.UNSET;\r
-               \r
+\r
                /**\r
                 * The source table for the columns defined as foreign.\r
                 */\r
@@ -391,7 +391,7 @@ public interface Iciql {
                 * The reference table for the columns defined as references.\r
                 */\r
                String referenceName() default "";\r
-               \r
+\r
                /**\r
                 * Columns defined as 'references'.\r
                 * <ul>\r
@@ -410,7 +410,7 @@ public interface Iciql {
        public @interface IQContraintsForeignKey {\r
                IQContraintForeignKey[] value() default {};\r
        }\r
-       \r
+\r
        /**\r
         * A unique constraint annotation.\r
         * <p>\r
@@ -447,7 +447,7 @@ public interface Iciql {
        public @interface IQContraintsUnique {\r
                IQContraintUnique[] value() default {};\r
        }\r
-       \r
+\r
        /**\r
         * Annotation to define a view.\r
         */\r
@@ -463,7 +463,7 @@ public interface Iciql {
                 * model class is not annotated with IQView. Default: unspecified.\r
                 */\r
                String name() default "";\r
-               \r
+\r
                /**\r
                 * The source table for the view.\r
                 * <p>\r
@@ -491,7 +491,7 @@ public interface Iciql {
                 */\r
                boolean annotationsOnly() default true;\r
        }\r
-       \r
+\r
        /**\r
         * String snippet defining SQL constraints for a field. Use "this" as\r
         * a placeholder for the column name.  "this" will be substituted at\r
@@ -507,8 +507,8 @@ public interface Iciql {
        public @interface IQConstraint {\r
 \r
                String value() default "";\r
-       }       \r
-       \r
+       }\r
+\r
        /**\r
         * Annotation to specify multiple indexes.\r
         */\r
@@ -657,7 +657,7 @@ public interface Iciql {
                 */\r
                String defaultValue() default "";\r
 \r
-       }       \r
+       }\r
 \r
        /**\r
         * Interface for using the EnumType.ENUMID enumeration mapping strategy.\r
@@ -665,19 +665,22 @@ public interface Iciql {
         * Enumerations wishing to use EnumType.ENUMID must implement this\r
         * interface.\r
         */\r
-       public interface EnumId {\r
-               int enumId();\r
+       public interface EnumId<X> {\r
+               X enumId();\r
+               Class<X> enumIdClass();\r
        }\r
 \r
+\r
+\r
        /**\r
         * Enumeration representing how to map a java.lang.Enum to a column.\r
         * <p>\r
         * <ul>\r
         * <li>NAME - name() : string\r
         * <li>ORDINAL - ordinal() : int\r
-        * <li>ENUMID - enumId() : int\r
+        * <li>ENUMID - enumId() : X\r
         * </ul>\r
-        * \r
+        *\r
         * @see com.iciql.Iciql.EnumId interface\r
         */\r
        public enum EnumType {\r
@@ -700,14 +703,14 @@ public interface Iciql {
         * annotation.\r
         * <p>\r
         * The default mapping is by NAME.\r
-        * \r
+        *\r
         * <pre>\r
         * IQEnum(EnumType.NAME)\r
         * </pre>\r
-        * \r
+        *\r
         * A string mapping will generate either a VARCHAR, if IQColumn.length > 0\r
         * or a TEXT column if IQColumn.length == 0\r
-        * \r
+        *\r
         */\r
        @Retention(RetentionPolicy.RUNTIME)\r
        @Target({ ElementType.FIELD, ElementType.TYPE })\r
@@ -720,9 +723,9 @@ public interface Iciql {
         */\r
        @Retention(RetentionPolicy.RUNTIME)\r
        @Target(ElementType.FIELD)\r
-       public @interface IQIgnore{     \r
+       public @interface IQIgnore{\r
        }\r
-       \r
+\r
        /**\r
         * This method is called to let the table define the primary key, indexes,\r
         * and the table name.\r
index 56e6440b1f21493037395402f896b8f4e9ddceca..c3fd8474cab17890fa49df285f16c837b90fdb2a 100644 (file)
@@ -147,7 +147,7 @@ class ModelUtils {
 
        /**
         * Returns a SQL type mapping for a Java class.
-        * 
+        *
         * @param fieldDef
         *            the field to map
         * @return
@@ -157,8 +157,14 @@ class ModelUtils {
                if (fieldClass.isEnum()) {
                        switch (fieldDef.enumType) {
                        case ORDINAL:
-                       case ENUMID:
                                return "INT";
+                       case ENUMID:
+                               String sqlType = SUPPORTED_TYPES.get(fieldDef.enumTypeClass);
+                               if (sqlType == null) {
+                                       throw new IciqlException("Unsupported enum mapping type {0} for {1}",
+                                                       fieldDef.enumTypeClass, fieldDef.columnName);
+                               }
+                               return sqlType;
                        case NAME:
                        default:
                                return "VARCHAR";
@@ -172,7 +178,7 @@ class ModelUtils {
 
        /**
         * Returns the Java class for a given SQL type.
-        * 
+        *
         * @param sqlType
         * @param dateTimeClass
         *            the preferred date class (java.util.Date or
@@ -211,7 +217,7 @@ class ModelUtils {
 
        /**
         * Tries to create a convert a SQL table name to a camel case class name.
-        * 
+        *
         * @param tableName
         *            the SQL table name
         * @return the class name
@@ -239,7 +245,7 @@ class ModelUtils {
 
        /**
         * Ensures that SQL column names don't collide with Java keywords.
-        * 
+        *
         * @param columnName
         *            the column name
         * @return the Java field name
@@ -254,7 +260,7 @@ class ModelUtils {
 
        /**
         * Converts a DEFAULT clause value into an object.
-        * 
+        *
         * @param field
         *            definition
         * @return object
@@ -360,7 +366,7 @@ class ModelUtils {
 
        /**
         * Converts the object into a DEFAULT clause value.
-        * 
+        *
         * @param o
         *            the default object
         * @return the value formatted for a DEFAULT clause
@@ -395,7 +401,7 @@ class ModelUtils {
 
        /**
         * Checks the formatting of IQColumn.defaultValue().
-        * 
+        *
         * @param defaultValue
         *            the default value
         * @return true if it is
@@ -412,7 +418,7 @@ class ModelUtils {
 
        /**
         * Checks to see if the default value matches the class.
-        * 
+        *
         * @param modelClass
         *            the class
         * @param defaultValue
index e0cc1690d8eaa005550e3b4f33dfb0992f45b900..0cb1ad27033076509861ee2c287d01ff130762cd 100644 (file)
@@ -37,11 +37,11 @@ import com.iciql.Iciql.EnumId;
 import com.iciql.Iciql.EnumType;\r
 import com.iciql.Iciql.IQColumn;\r
 import com.iciql.Iciql.IQConstraint;\r
+import com.iciql.Iciql.IQContraintForeignKey;\r
 import com.iciql.Iciql.IQContraintUnique;\r
+import com.iciql.Iciql.IQContraintsForeignKey;\r
 import com.iciql.Iciql.IQContraintsUnique;\r
 import com.iciql.Iciql.IQEnum;\r
-import com.iciql.Iciql.IQContraintForeignKey;\r
-import com.iciql.Iciql.IQContraintsForeignKey;\r
 import com.iciql.Iciql.IQIgnore;\r
 import com.iciql.Iciql.IQIndex;\r
 import com.iciql.Iciql.IQIndexes;\r
@@ -58,7 +58,7 @@ import com.iciql.util.Utils;
 /**\r
  * A table definition contains the index definitions of a table, the field\r
  * definitions, the table name, and other meta data.\r
- * \r
+ *\r
  * @param <T>\r
  *            the table type\r
  */\r
@@ -79,7 +79,7 @@ public class TableDefinition<T> {
        /**\r
         * The meta data of a constraint on foreign key.\r
         */\r
-       \r
+\r
        public static class ConstraintForeignKeyDefinition {\r
 \r
                public String constraintName;\r
@@ -90,18 +90,18 @@ public class TableDefinition<T> {
                public ConstraintUpdateType updateType = ConstraintUpdateType.UNSET;\r
                public ConstraintDeferrabilityType deferrabilityType = ConstraintDeferrabilityType.UNSET;\r
        }\r
-       \r
+\r
        /**\r
         * The meta data of a unique constraint.\r
         */\r
-       \r
+\r
        public static class ConstraintUniqueDefinition {\r
 \r
                public String constraintName;\r
                public List<String> uniqueColumns;\r
        }\r
-       \r
-       \r
+\r
+\r
        /**\r
         * The meta data of a field.\r
         */\r
@@ -118,6 +118,7 @@ public class TableDefinition<T> {
                boolean nullable;\r
                String defaultValue;\r
                EnumType enumType;\r
+               Class<?> enumTypeClass;\r
                boolean isPrimitive;\r
                String constraint;\r
 \r
@@ -161,12 +162,12 @@ public class TableDefinition<T> {
                                throw new IciqlException(e);\r
                        }\r
                }\r
-               \r
+\r
                @Override\r
                public int hashCode() {\r
                        return columnName.hashCode();\r
                }\r
-               \r
+\r
                @Override\r
                public boolean equals(Object o) {\r
                        if (o instanceof FieldDefinition) {\r
@@ -228,7 +229,7 @@ public class TableDefinition<T> {
 \r
        /**\r
         * Define a primary key by the specified model fields.\r
-        * \r
+        *\r
         * @param modelFields\r
         *            the ordered list of model fields\r
         */\r
@@ -239,7 +240,7 @@ public class TableDefinition<T> {
 \r
        /**\r
         * Define a primary key by the specified column names.\r
-        * \r
+        *\r
         * @param columnNames\r
         *            the ordered list of column names\r
         */\r
@@ -270,7 +271,7 @@ public class TableDefinition<T> {
 \r
        /**\r
         * Defines an index with the specified model fields.\r
-        * \r
+        *\r
         * @param name\r
         *            the index name (optional)\r
         * @param type\r
@@ -285,7 +286,7 @@ public class TableDefinition<T> {
 \r
        /**\r
         * Defines an index with the specified column names.\r
-        * \r
+        *\r
         * @param type\r
         *            the index type (STANDARD, HASH, UNIQUE, UNIQUE_HASH)\r
         * @param columnNames\r
@@ -305,7 +306,7 @@ public class TableDefinition<T> {
 \r
        /**\r
         * Defines an unique constraint with the specified model fields.\r
-        * \r
+        *\r
         * @param name\r
         *            the constraint name (optional)\r
         * @param modelFields\r
@@ -318,7 +319,7 @@ public class TableDefinition<T> {
 \r
        /**\r
         * Defines an unique constraint.\r
-        * \r
+        *\r
         * @param name\r
         * @param columnNames\r
         */\r
@@ -335,7 +336,7 @@ public class TableDefinition<T> {
 \r
        /**\r
         * Defines a foreign key constraint with the specified model fields.\r
-        * \r
+        *\r
         * @param name\r
         *            the constraint name (optional)\r
         * @param modelFields\r
@@ -426,7 +427,7 @@ public class TableDefinition<T> {
                if (inheritColumns) {\r
                        Class<?> superClass = clazz.getSuperclass();\r
                        classFields.addAll(Arrays.asList(superClass.getDeclaredFields()));\r
-                       \r
+\r
                        if (superClass.isAnnotationPresent(IQView.class)) {\r
                                IQView superView = superClass.getAnnotation(IQView.class);\r
                                if (superView.inheritColumns()) {\r
@@ -461,6 +462,7 @@ public class TableDefinition<T> {
                        boolean trim = false;\r
                        boolean nullable = !f.getType().isPrimitive();\r
                        EnumType enumType = null;\r
+                       Class<?> enumTypeClass = null;\r
                        String defaultValue = "";\r
                        String constraint = "";\r
                        // configure Java -> SQL enum mapping\r
@@ -476,6 +478,11 @@ public class TableDefinition<T> {
                                        IQEnum iqenum = f.getAnnotation(IQEnum.class);\r
                                        enumType = iqenum.value();\r
                                }\r
+\r
+                               if (EnumId.class.isAssignableFrom(f.getType())) {\r
+                                       // custom enumid mapping\r
+                                       enumTypeClass = ((EnumId<?>) f.getType().getEnumConstants()[0]).enumIdClass();\r
+                               }\r
                        }\r
 \r
                        // try using default object\r
@@ -515,7 +522,7 @@ public class TableDefinition<T> {
                                        defaultValue = col.defaultValue();\r
                                }\r
                        }\r
-                       \r
+\r
                        boolean hasConstraint = f.isAnnotationPresent(IQConstraint.class);\r
                        if (hasConstraint) {\r
                                IQConstraint con = f.getAnnotation(IQConstraint.class);\r
@@ -539,13 +546,14 @@ public class TableDefinition<T> {
                                fieldDef.nullable = nullable;\r
                                fieldDef.defaultValue = defaultValue;\r
                                fieldDef.enumType = enumType;\r
+                               fieldDef.enumTypeClass = enumTypeClass;\r
                                fieldDef.dataType = ModelUtils.getDataType(fieldDef);\r
                                fieldDef.constraint = constraint;\r
                                uniqueFields.add(fieldDef);\r
                        }\r
                }\r
                fields.addAll(uniqueFields);\r
-               \r
+\r
                List<String> primaryKey = Utils.newArrayList();\r
                int primitiveBoolean = 0;\r
                for (FieldDefinition fieldDef : fields) {\r
@@ -623,7 +631,7 @@ public class TableDefinition<T> {
                                if (!EnumId.class.isAssignableFrom(value.getClass())) {\r
                                        throw new IciqlException(field.field.getName() + " does not implement EnumId!");\r
                                }\r
-                               EnumId enumid = (EnumId) value;\r
+                               EnumId<?> enumid = (EnumId<?>) value;\r
                                return enumid.enumId();\r
                        }\r
                }\r
@@ -643,7 +651,7 @@ public class TableDefinition<T> {
                // return the value unchanged\r
                return value;\r
        }\r
-       \r
+\r
        PreparedStatement createInsertStatement(Db db, Object obj, boolean returnKey) {\r
                SQLStatement stat = new SQLStatement(db);\r
                StatementBuilder buff = new StatementBuilder("INSERT INTO ");\r
@@ -896,7 +904,7 @@ public class TableDefinition<T> {
                                }\r
                        }\r
                }\r
-               \r
+\r
                // create foreign keys constraints\r
                for (ConstraintForeignKeyDefinition constraint : constraintsForeignKey) {\r
                        stat = new SQLStatement(db);\r
@@ -1004,17 +1012,17 @@ public class TableDefinition<T> {
                                                viewTableName = parentView.tableName();\r
                                        }\r
                                }\r
-                               \r
+\r
                                if (StringUtils.isNullOrEmpty(viewTableName)) {\r
                                        // still missing view table name\r
                                        throw new IciqlException("View model class \"{0}\" is missing a table name!", tableName);\r
                                }\r
                        }\r
-                       \r
+\r
                        // allow control over createTableIfRequired()\r
                        createIfRequired = viewAnnotation.create();\r
                }\r
-               \r
+\r
                if (clazz.isAnnotationPresent(IQIndex.class)) {\r
                        // single table index\r
                        IQIndex index = clazz.getAnnotation(IQIndex.class);\r
@@ -1028,7 +1036,7 @@ public class TableDefinition<T> {
                                addIndex(index);\r
                        }\r
                }\r
-               \r
+\r
                if (clazz.isAnnotationPresent(IQContraintUnique.class)) {\r
                        // single table unique constraint\r
                        IQContraintUnique constraint = clazz.getAnnotation(IQContraintUnique.class);\r
@@ -1042,7 +1050,7 @@ public class TableDefinition<T> {
                                addConstraintUnique(constraint);\r
                        }\r
                }\r
-               \r
+\r
                if (clazz.isAnnotationPresent(IQContraintForeignKey.class)) {\r
                        // single table constraint\r
                        IQContraintForeignKey constraint = clazz.getAnnotation(IQContraintForeignKey.class);\r
@@ -1056,7 +1064,7 @@ public class TableDefinition<T> {
                                addConstraintForeignKey(constraint);\r
                        }\r
                }\r
-               \r
+\r
        }\r
 \r
        private void addConstraintForeignKey(IQContraintForeignKey constraint) {\r
@@ -1064,15 +1072,15 @@ public class TableDefinition<T> {
                List<String> referenceColumns = Arrays.asList(constraint.referenceColumns());\r
                addConstraintForeignKey(constraint.name(), foreignColumns, constraint.referenceName(), referenceColumns, constraint.deleteType(), constraint.updateType(), constraint.deferrabilityType());\r
        }\r
-       \r
+\r
        private void addConstraintUnique(IQContraintUnique constraint) {\r
                List<String> uniqueColumns = Arrays.asList(constraint.uniqueColumns());\r
                addConstraintUnique(constraint.name(), uniqueColumns);\r
        }\r
-       \r
+\r
        /**\r
         * Defines a foreign key constraint with the specified parameters.\r
-        * \r
+        *\r
         * @param name\r
         *            name of the constraint\r
         * @param foreignColumns\r
@@ -1119,11 +1127,11 @@ public class TableDefinition<T> {
        List<ConstraintUniqueDefinition> getContraintsUnique() {\r
                return constraintsUnique;\r
        }\r
-       \r
+\r
        List<ConstraintForeignKeyDefinition> getContraintsForeignKey() {\r
                return constraintsForeignKey;\r
        }\r
-       \r
+\r
        private void initObject(Object obj, Map<Object, FieldDefinition> map) {\r
                for (FieldDefinition def : fields) {\r
                        Object newValue = def.initWithNewObject(obj);\r
@@ -1152,13 +1160,13 @@ public class TableDefinition<T> {
         * JaQu assumed that you can always use the integer index of the\r
         * reflectively mapped field definition to determine position in the result\r
         * set.\r
-        * \r
+        *\r
         * This is not always true.\r
-        * \r
+        *\r
         * iciql identifies when a select * query is executed and maps column names\r
         * to a column index from the result set. If the select statement is\r
         * explicit, then the standard assumed column index is used instead.\r
-        * \r
+        *\r
         * @param rs\r
         * @return\r
         */\r
index 64fe6b3cd6671ec254237ae0cbbb1a539c08b83f..5b2914a8058b61d06f7f5922018806f7a79da520 100644 (file)
@@ -135,8 +135,8 @@ public class Utils {
                                                }\r
                                        }\r
                                        throw new IciqlException(e,\r
-                                                       "Missing default constructor?  Exception trying to instantiate {0}: {1}",\r
-                                                       clazz.getName(), e.getMessage());\r
+                                                       "Missing default constructor?  Exception trying to instantiate {0}: {1}", clazz.getName(),\r
+                                                       e.getMessage());\r
                                }\r
                        }\r
                };\r
@@ -214,8 +214,7 @@ public class Utils {
                                        }\r
                                }\r
                        }\r
-                       throw new IciqlException(e,\r
-                                       "Missing default constructor?! Exception trying to instantiate {0}: {1}",\r
+                       throw new IciqlException(e, "Missing default constructor?! Exception trying to instantiate {0}: {1}",\r
                                        clazz.getName(), e.getMessage());\r
                }\r
        }\r
@@ -337,7 +336,7 @@ public class Utils {
                        if (!EnumId.class.isAssignableFrom(o.getClass())) {\r
                                throw new IciqlException("Can not convert the enum {0} using ENUMID", o);\r
                        }\r
-                       EnumId enumid = (EnumId) o;\r
+                       EnumId<?> enumid = (EnumId<?>) o;\r
                        return enumid.enumId();\r
                case NAME:\r
                default:\r
@@ -367,17 +366,39 @@ public class Utils {
                        }\r
 \r
                        // find name match\r
-                       for (Enum<?> value : values) {\r
-                               if (value.name().equalsIgnoreCase(name)) {\r
-                                       return value;\r
+                       if (type.equals(EnumType.ENUMID)) {\r
+                               // ENUMID mapping\r
+                               for (Enum<?> value : values) {\r
+                                       EnumId<?> enumid = (EnumId<?>) value;\r
+                                       if (enumid.enumId().equals(name)) {\r
+                                               return value;\r
+                                       }\r
+                               }\r
+                       } else if (type.equals(EnumType.NAME)) {\r
+                               // standard Enum.name() mapping\r
+                               for (Enum<?> value : values) {\r
+                                       if (value.name().equalsIgnoreCase(name)) {\r
+                                               return value;\r
+                                       }\r
                                }\r
                        }\r
                } else if (String.class.isAssignableFrom(currentType)) {\r
                        // VARCHAR field\r
                        String name = (String) o;\r
-                       for (Enum<?> value : values) {\r
-                               if (value.name().equalsIgnoreCase(name)) {\r
-                                       return value;\r
+                       if (type.equals(EnumType.ENUMID)) {\r
+                               // ENUMID mapping\r
+                               for (Enum<?> value : values) {\r
+                                       EnumId<?> enumid = (EnumId<?>) value;\r
+                                       if (enumid.enumId().equals(name)) {\r
+                                               return value;\r
+                                       }\r
+                               }\r
+                       } else if (type.equals(EnumType.NAME)) {\r
+                               // standard Enum.name() mapping\r
+                               for (Enum<?> value : values) {\r
+                                       if (value.name().equalsIgnoreCase(name)) {\r
+                                               return value;\r
+                                       }\r
                                }\r
                        }\r
                } else if (Number.class.isAssignableFrom(currentType)) {\r
@@ -397,8 +418,23 @@ public class Utils {
                                }\r
                                // ENUMID mapping\r
                                for (Enum<?> value : values) {\r
-                                       EnumId enumid = (EnumId) value;\r
-                                       if (enumid.enumId() == n) {\r
+                                       EnumId<?> enumid = (EnumId<?>) value;\r
+                                       if (enumid.enumId().equals(n)) {\r
+                                               return value;\r
+                                       }\r
+                               }\r
+                       }\r
+               } else {\r
+                       // custom object mapping\r
+                       if (type.equals(EnumType.ENUMID)) {\r
+                               if (!EnumId.class.isAssignableFrom(targetType)) {\r
+                                       throw new IciqlException("Can not convert the value {0} from {1} to {2} using ENUMID", o,\r
+                                                       currentType, targetType);\r
+                               }\r
+                               // ENUMID mapping\r
+                               for (Enum<?> value : values) {\r
+                                       EnumId<?> enumid = (EnumId<?>) value;\r
+                                       if (enumid.enumId().equals(o)) {\r
                                                return value;\r
                                        }\r
                                }\r
@@ -456,8 +492,7 @@ public class Utils {
                                length = Integer.MAX_VALUE;\r
                        }\r
                        int block = Math.min(BUFFER_BLOCK_SIZE, length);\r
-                       ByteArrayOutputStream out = new ByteArrayOutputStream(length == Integer.MAX_VALUE ? block\r
-                                       : length);\r
+                       ByteArrayOutputStream out = new ByteArrayOutputStream(length == Integer.MAX_VALUE ? block : length);\r
                        byte[] buff = new byte[block];\r
                        while (length > 0) {\r
                                int len = Math.min(block, length);\r
index d8a05896d0b28146edf4f63f98a1ae974b3b2141..8e1f90e29eab0354bc454048f12ed1369eed63bc 100644 (file)
@@ -31,6 +31,7 @@ import com.iciql.test.models.EnumModels;
 import com.iciql.test.models.EnumModels.EnumIdModel;\r
 import com.iciql.test.models.EnumModels.EnumOrdinalModel;\r
 import com.iciql.test.models.EnumModels.EnumStringModel;\r
+import com.iciql.test.models.EnumModels.Genus;\r
 import com.iciql.test.models.EnumModels.Tree;\r
 \r
 /**\r
@@ -58,6 +59,7 @@ public class EnumsTest {
                testIntEnums(new EnumIdModel());\r
                testIntEnums(new EnumOrdinalModel());\r
                testStringEnums(new EnumStringModel());\r
+               testStringEnumIds(new EnumStringModel());\r
        }\r
 \r
        private void testIntEnums(EnumModels e) {\r
@@ -110,7 +112,31 @@ public class EnumsTest {
                list = db.from(e).where(e.tree()).between(Tree.MAPLE).and(Tree.PINE).select();\r
                assertEquals(3, list.size());\r
        }\r
-       \r
+\r
+       private void testStringEnumIds(EnumModels e) {\r
+               // ensure all records inserted\r
+               long count = db.from(e).selectCount();\r
+               assertEquals(5, count);\r
+\r
+               // special case:\r
+               // value is first enum constant which is also the alias object.\r
+               // the first enum constant is used as the alias because we can not\r
+               // instantiate an enum reflectively.\r
+               EnumModels firstEnumValue = db.from(e).where(e.genus()).is(Genus.PINUS).selectFirst();\r
+               assertEquals(Tree.PINE, firstEnumValue.tree());\r
+               assertEquals(Genus.PINUS, firstEnumValue.genus());\r
+\r
+               EnumModels model = db.from(e).where(e.genus()).is(Genus.JUGLANS).selectFirst();\r
+\r
+               assertEquals(400, model.id.intValue());\r
+               assertEquals(Tree.WALNUT, model.tree());\r
+               assertEquals(Genus.JUGLANS, model.genus());\r
+\r
+               List<EnumModels> list = db.from(e).where(e.genus()).isNot(Genus.BETULA).select();\r
+               assertEquals(count - 1, list.size());\r
+\r
+       }\r
+\r
        @Test\r
        public void testMultipleEnumInstances() {\r
                BadEnums b = new BadEnums();\r
@@ -121,7 +147,7 @@ public class EnumsTest {
                        assertTrue(e.getMessage(), e.getMessage().startsWith("Can not explicitly reference Tree"));\r
                }\r
        }\r
-       \r
+\r
        public static class BadEnums {\r
                Tree tree1 = Tree.BIRCH;\r
                Tree tree2 = Tree.MAPLE;\r
index a865f6c264e25d1d63b55c43c2dc472fd391c122..232073477ad2f2afb96b09748c7da92fc01660a9 100644 (file)
@@ -34,14 +34,14 @@ public abstract class EnumModels {
        /**\r
         * Test of @IQEnum annotated enumeration. This strategy is the default\r
         * strategy for all fields of the Tree enum.\r
-        * \r
+        *\r
         * Individual Tree field declarations can override this strategy by\r
         * specifying a different @IQEnum annotation.\r
-        * \r
+        *\r
         * Here ORDINAL specifies that this enum will be mapped to an INT column.\r
         */\r
        @IQEnum(EnumType.ENUMID)\r
-       public enum Tree implements EnumId {\r
+       public enum Tree implements EnumId<Integer> {\r
                PINE(10), OAK(20), BIRCH(30), WALNUT(40), MAPLE(50);\r
 \r
                private int enumid;\r
@@ -51,9 +51,39 @@ public abstract class EnumModels {
                }\r
 \r
                @Override\r
-               public int enumId() {\r
+               public Integer enumId() {\r
                        return enumid;\r
                }\r
+\r
+               @Override\r
+               public Class<Integer> enumIdClass() {\r
+                       return Integer.class;\r
+               }\r
+\r
+       }\r
+\r
+       /**\r
+        * Enum for testing custom ENUMID mapping.\r
+        */\r
+       @IQEnum(EnumType.ENUMID)\r
+       public enum Genus implements EnumId<String> {\r
+               PINUS("pinaceae"), QUERCUS("fagaceae"), BETULA("betulaceae"), JUGLANS("juglandaceae"), ACER("aceraceae");\r
+\r
+               private String family;\r
+\r
+               Genus(String id) {\r
+                       this.family = id;\r
+               }\r
+\r
+               @Override\r
+               public String enumId() {\r
+                       return family;\r
+               }\r
+\r
+               @Override\r
+               public Class<String> enumIdClass() {\r
+                       return String.class;\r
+               }\r
        }\r
 \r
        @IQColumn(primaryKey = true)\r
@@ -61,6 +91,8 @@ public abstract class EnumModels {
 \r
        public abstract Tree tree();\r
 \r
+       public abstract Genus genus();\r
+\r
        /**\r
         * Test model for enum-as-enumid.\r
         */\r
@@ -72,12 +104,18 @@ public abstract class EnumModels {
                @IQColumn\r
                private Tree tree;\r
 \r
+               // no need to specify ENUMID type as the enumeration definition\r
+               // specifies it.\r
+               @IQColumn\r
+               private Genus genus;\r
+\r
                public EnumIdModel() {\r
                }\r
 \r
-               public EnumIdModel(int id, Tree tree) {\r
+               public EnumIdModel(int id, Tree tree, Genus genus) {\r
                        this.id = id;\r
                        this.tree = tree;\r
+                       this.genus = genus;\r
                }\r
 \r
                @Override\r
@@ -85,10 +123,17 @@ public abstract class EnumModels {
                        return tree;\r
                }\r
 \r
+               @Override\r
+               public Genus genus() {\r
+                       return genus;\r
+               }\r
+\r
                public static List<EnumIdModel> createList() {\r
-                       return Arrays.asList(new EnumIdModel(400, Tree.WALNUT), new EnumIdModel(200, Tree.OAK),\r
-                                       new EnumIdModel(500, Tree.MAPLE), new EnumIdModel(300, Tree.BIRCH), new EnumIdModel(100,\r
-                                                       Tree.PINE));\r
+                       return Arrays.asList(new EnumIdModel(400, Tree.WALNUT, Genus.JUGLANS),\r
+                                       new EnumIdModel(200, Tree.OAK, Genus.QUERCUS),\r
+                                       new EnumIdModel(500, Tree.MAPLE, Genus.ACER),\r
+                                       new EnumIdModel(300, Tree.BIRCH, Genus.BETULA),\r
+                                       new EnumIdModel(100, Tree.PINE, Genus.PINUS));\r
                }\r
        }\r
 \r
@@ -103,10 +148,13 @@ public abstract class EnumModels {
                @IQColumn\r
                private Tree tree;\r
 \r
+               @IQColumn\r
+               private Genus genus;\r
+\r
                public EnumOrdinalModel() {\r
                }\r
 \r
-               public EnumOrdinalModel(int id, Tree tree) {\r
+               public EnumOrdinalModel(int id, Tree tree, Genus genus) {\r
                        this.id = id;\r
                        this.tree = tree;\r
                }\r
@@ -116,10 +164,17 @@ public abstract class EnumModels {
                        return tree;\r
                }\r
 \r
+               @Override\r
+               public Genus genus() {\r
+                       return genus;\r
+               }\r
+\r
                public static List<EnumOrdinalModel> createList() {\r
-                       return Arrays.asList(new EnumOrdinalModel(400, Tree.WALNUT), new EnumOrdinalModel(200, Tree.OAK),\r
-                                       new EnumOrdinalModel(500, Tree.MAPLE), new EnumOrdinalModel(300, Tree.BIRCH),\r
-                                       new EnumOrdinalModel(100, Tree.PINE));\r
+                       return Arrays.asList(new EnumOrdinalModel(400, Tree.WALNUT, Genus.JUGLANS),\r
+                                       new EnumOrdinalModel(200, Tree.OAK, Genus.QUERCUS),\r
+                                       new EnumOrdinalModel(500, Tree.MAPLE, Genus.ACER),\r
+                                       new EnumOrdinalModel(300, Tree.BIRCH, Genus.BETULA),\r
+                                       new EnumOrdinalModel(100, Tree.PINE, Genus.PINUS));\r
                }\r
        }\r
 \r
@@ -135,12 +190,16 @@ public abstract class EnumModels {
                @IQColumn(length = 25)\r
                private Tree tree;\r
 \r
+               @IQColumn(trim = true, length = 25)\r
+               private Genus genus;\r
+\r
                public EnumStringModel() {\r
                }\r
 \r
-               public EnumStringModel(int id, Tree tree) {\r
+               public EnumStringModel(int id, Tree tree, Genus genus) {\r
                        this.id = id;\r
                        this.tree = tree;\r
+                       this.genus = genus;\r
                }\r
 \r
                @Override\r
@@ -148,10 +207,17 @@ public abstract class EnumModels {
                        return tree;\r
                }\r
 \r
+               @Override\r
+               public Genus genus() {\r
+                       return genus;\r
+               }\r
+\r
                public static List<EnumStringModel> createList() {\r
-                       return Arrays.asList(new EnumStringModel(400, Tree.WALNUT), new EnumStringModel(200, Tree.OAK),\r
-                                       new EnumStringModel(500, Tree.MAPLE), new EnumStringModel(300, Tree.BIRCH),\r
-                                       new EnumStringModel(100, Tree.PINE));\r
+                       return Arrays.asList(new EnumStringModel(400, Tree.WALNUT, Genus.JUGLANS),\r
+                                       new EnumStringModel(200, Tree.OAK, Genus.QUERCUS),\r
+                                       new EnumStringModel(500, Tree.MAPLE, Genus.ACER),\r
+                                       new EnumStringModel(300, Tree.BIRCH, Genus.BETULA),\r
+                                       new EnumStringModel(100, Tree.PINE, Genus.PINUS));\r
                }\r
        }\r
 }\r