]> source.dussan.org Git - iciql.git/commitdiff
BLOB support (issue 1) and Enum support (issue 2). Documentation.
authorJames Moger <james.moger@gmail.com>
Thu, 4 Aug 2011 21:58:22 +0000 (17:58 -0400)
committerJames Moger <james.moger@gmail.com>
Thu, 4 Aug 2011 21:58:22 +0000 (17:58 -0400)
13 files changed:
build.xml
docs/01_model_classes.mkd
docs/05_releases.mkd
src/com/iciql/Iciql.java
src/com/iciql/ModelUtils.java
src/com/iciql/Query.java
src/com/iciql/TableDefinition.java
src/com/iciql/TableInspector.java
src/com/iciql/build/BuildSite.java
src/com/iciql/util/Utils.java
tests/com/iciql/test/ModelsTest.java
tests/com/iciql/test/models/ProductAnnotationOnly.java
tests/com/iciql/test/models/SupportedTypes.java

index 8c7eaec0aaac54acf45ab5dae46dfb3fbf852aff..18698c663cde505ab2760fe36bdfef638e5e73bc 100644 (file)
--- a/build.xml
+++ b/build.xml
 \r
                        <arg value="--substitute" />\r
                        <arg value="%ENDCODE%=&lt;/pre&gt;" />\r
+                       \r
+                       <arg value="--regex" />\r
+                       <arg value="&quot;\b(issue)(\s*[#]?|-){0,1}(\d+)\b!!!&lt;a href='http://code.google.com/p/iciql/issues/detail?id=$3'&gt;issue $3&lt;/a&gt;&quot;" />\r
+\r
                </java> \r
        </target>\r
 \r
index a0db6a1d1ca03d1ec4321a31905d99a4a3d29b1b..8afcfa829eaf5a92c913219ffdaf670994dc60a8 100644 (file)
@@ -47,6 +47,12 @@ Alternatively, model classes can be automatically generated by iciql using the m
 <tr><td>java.util.Date</td>\r
 <td>TIMESTAMP</td></tr>\r
 \r
+<tr><td>byte []</td>\r
+<td>BLOB</td></tr>\r
+\r
+<tr><td>java.lang.Enum</td>\r
+<td>VARCHAR/TEXT *@IQEnum(STRING)* or INT *@IQEnum(ORDINAL)*</td></tr>\r
+\r
 </table>\r
 \r
 **NOTE:**<br/>\r
@@ -55,7 +61,6 @@ Please consult the `com.iciql.ModelUtils` class for details.
 \r
 ### Unsupported Types\r
 - Java primitives (use their object counterparts instead)\r
-- binary types (BLOB, etc)\r
 - array types\r
 - custom types\r
 \r
@@ -83,7 +88,9 @@ The recommended approach to setup a model class is to annotate the class and fie
  \r
 ### Example Annotated Model\r
 %BEGINCODE%\r
+import com.iciql.Iciql.EnumType;\r
 import com.iciql.Iciql.IQColumn;\r
+import com.iciql.Iciql.IQEnum;\r
 import com.iciql.Iciql.IQIndex;\r
 import com.iciql.Iciql.IQTable;\r
 \r
@@ -94,6 +101,11 @@ import com.iciql.Iciql.IQTable;
 })\r
 public class Product {\r
 \r
+       @IQEnum(EnumType.ORDINAL)\r
+       public enum Availability {\r
+               ACTIVE, DISCONTINUED;\r
+       }\r
+\r
        @IQColumn(primaryKey = true)\r
        public Integer productId;\r
       \r
@@ -111,6 +123,9 @@ public class Product {
       \r
        @IQColumn\r
        private Integer reorderQuantity;\r
+       \r
+       @IQColumn\r
+       private Availability availability;\r
       \r
        public Product() {\r
                // default constructor\r
index db29860af9bf5826011ab495fbc536649ade437f..50fda43efa9ca89eef2311a0ca71eda8c9013eb5 100644 (file)
@@ -3,6 +3,8 @@
 ### Current Release\r
 **%VERSION%** ([zip](http://code.google.com/p/iciql/downloads/detail?name=%ZIP%)|[jar](http://code.google.com/p/iciql/downloads/detail?name=%JAR%)) &nbsp; *released %BUILDDATE%*\r
 \r
+- added BLOB support (issue 1)\r
+- added java.lang.Enum support (issue 2)\r
 - api change release (API v2)\r
 - annotations overhaul to reduce verbosity\r
     - @IQSchema(name="public") -> @IQSchema("public")\r
index 35ad8ccccc4080f40ec713223dc39aef3d822910..8d71aa6f46f4c2748b7ee3a0da5209f75493f9eb 100644 (file)
@@ -87,9 +87,13 @@ import java.lang.annotation.Target;
  * <td>java.util.Date</td>\r
  * <td>TIMESTAMP</td>\r
  * </tr>\r
+ * <tr>\r
+ * <td>byte []</td>\r
+ * <td>BLOB</td>\r
+ * </tr>\r
  * </table>\r
  * <p>\r
- * Unsupported data types: binary types (BLOB, etc), and custom types.\r
+ * Unsupported data types: java.lang.Enum, Array Types, and custom types.\r
  * <p>\r
  * Table and field mapping: by default, the mapped table name is the class name\r
  * and the public fields are reflectively mapped, by their name, to columns. As\r
@@ -142,6 +146,7 @@ public interface Iciql {
        /**\r
         * An annotation for an iciql version.\r
         * <p>\r
+        * \r
         * @IQVersion(1)\r
         */\r
        @Retention(RetentionPolicy.RUNTIME)\r
@@ -162,6 +167,7 @@ public interface Iciql {
        /**\r
         * An annotation for a schema.\r
         * <p>\r
+        * \r
         * @IQSchema("PUBLIC")\r
         */\r
        @Retention(RetentionPolicy.RUNTIME)\r
@@ -189,7 +195,8 @@ public interface Iciql {
         * <li>@IQIndex("name")\r
         * <li>@IQIndex({"street", "city"})\r
         * <li>@IQIndex(name="streetidx", value={"street", "city"})\r
-        * <li>@IQIndex(name="addressidx", type=IndexType.UNIQUE, value={"house_number", "street", "city"})\r
+        * <li>@IQIndex(name="addressidx", type=IndexType.UNIQUE,\r
+        * value={"house_number", "street", "city"})\r
         * </ul>\r
         */\r
        @Retention(RetentionPolicy.RUNTIME)\r
@@ -365,6 +372,47 @@ public interface Iciql {
 \r
        }\r
 \r
+       /**\r
+        * Enumeration representing now to map a java.lang.Enum to a column.\r
+        * <p>\r
+        * <ul>\r
+        * <li>STRING\r
+        * <li>ORDINAL\r
+        * </ul>\r
+        */\r
+       public enum EnumType {\r
+               STRING, ORDINAL;\r
+       }\r
+\r
+       /**\r
+        * Annotation to define how a java.lang.Enum is mapped to a column.\r
+        * <p>\r
+        * This annotation can be used on:\r
+        * <ul>\r
+        * <li>a field instance of an enumeration type\r
+        * <li>on the enumeration class declaration\r
+        * </ul>\r
+        * If you choose to annotate the class declaration, that will be the default\r
+        * mapping strategy for all @IQColumn instances of the enum. This can still\r
+        * be overridden for an individual field by specifying the IQEnum\r
+        * annotation.\r
+        * <p>\r
+        * The default mapping is by STRING.\r
+        * \r
+        * <pre>\r
+        * IQEnum(EnumType.STRING)\r
+        * </pre>\r
+        * \r
+        * A string mapping will generate either a VARCHAR, if IQColumn.maxLength >\r
+        * 0 or a TEXT column if IQColumn.maxLength == 0\r
+        * \r
+        */\r
+       @Retention(RetentionPolicy.RUNTIME)\r
+       @Target({ ElementType.FIELD, ElementType.TYPE })\r
+       public @interface IQEnum {\r
+               EnumType value() default EnumType.STRING;\r
+       }\r
+\r
        /**\r
         * This method is called to let the table define the primary key, indexes,\r
         * and the table name.\r
index 6b28f0e54df566680f5d4dc138c971f8ef014002..45a488272ff86b923f5dea879f8293fdab9851c2 100644 (file)
@@ -57,7 +57,7 @@ class ModelUtils {
                m.put(java.util.Date.class, "TIMESTAMP");
                m.put(java.sql.Date.class, "DATE");
                m.put(java.sql.Time.class, "TIME");
-               // TODO add blobs, binary types, custom types?
+               m.put(byte[].class, "BLOB");
        }
 
        /**
@@ -111,14 +111,21 @@ class ModelUtils {
                // date
                m.put("DATETIME", "TIMESTAMP");
                m.put("SMALLDATETIME", "TIMESTAMP");
+
+               // binary types
+               m.put("TINYBLOB", "BLOB");
+               m.put("MEDIUMBLOB", "BLOB");
+               m.put("LONGBLOB", "BLOB");
+               m.put("IMAGE", "BLOB");
+               m.put("OID", "BLOB");
        }
 
-       private static final List<String> KEYWORDS = Arrays.asList("abstract", "assert", "boolean", "break", "byte",
-                       "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else", "enum",
-                       "extends", "final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof", "int",
-                       "interface", "long", "native", "new", "package", "private", "protected", "public", "return", "short",
-                       "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "try",
-                       "void", "volatile", "while", "false", "null", "true");
+       private static final List<String> KEYWORDS = Arrays.asList("abstract", "assert", "boolean", "break",
+                       "byte", "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else",
+                       "enum", "extends", "final", "finally", "float", "for", "goto", "if", "implements", "import",
+                       "instanceof", "int", "interface", "long", "native", "new", "package", "private", "protected",
+                       "public", "return", "short", "static", "strictfp", "super", "switch", "synchronized", "this",
+                       "throw", "throws", "transient", "try", "void", "volatile", "while", "false", "null", "true");
 
        /**
         * Returns a SQL type mapping for a Java class.
@@ -131,6 +138,20 @@ class ModelUtils {
         */
        static String getDataType(FieldDefinition fieldDef, boolean strictTypeMapping) {
                Class<?> fieldClass = fieldDef.field.getType();
+               if (fieldClass.isEnum()) {
+                       if (fieldDef.enumType == null) {
+                               throw new IciqlException(fieldDef.field.getName() + " enum field does not specify @IQEnum!");
+                       }
+                       switch (fieldDef.enumType) {
+                       case STRING:
+                               if (fieldDef.maxLength <= 0) {
+                                       return "TEXT";
+                               }
+                               return "VARCHAR";
+                       case ORDINAL:
+                               return "INT";
+                       }
+               }
                if (SUPPORTED_TYPES.containsKey(fieldClass)) {
                        String type = SUPPORTED_TYPES.get(fieldClass);
                        if (type.equals("VARCHAR") && fieldDef.maxLength <= 0) {
@@ -228,7 +249,8 @@ class ModelUtils {
                }
                Pattern literalDefault = Pattern.compile("'.*'");
                Pattern functionDefault = Pattern.compile("[^'].*[^']");
-               return literalDefault.matcher(defaultValue).matches() || functionDefault.matcher(defaultValue).matches();
+               return literalDefault.matcher(defaultValue).matches()
+                               || functionDefault.matcher(defaultValue).matches();
        }
 
        /**
index 97e143bed6703dfe506634673cf6017a6bd4360b..d9dc84f8c9a090995d898e82369cb6f8a748b087 100644 (file)
@@ -18,6 +18,7 @@
 package com.iciql;\r
 \r
 import java.lang.reflect.Field;\r
+import java.sql.Blob;\r
 import java.sql.Clob;\r
 import java.sql.ResultSet;\r
 import java.sql.SQLException;\r
@@ -223,6 +224,8 @@ public class Query<T> {
                                        Object o = rs.getObject(1);\r
                                        if (Clob.class.isAssignableFrom(o.getClass())) {\r
                                                value = (X) Utils.convert(o, String.class);\r
+                                       } else if (Blob.class.isAssignableFrom(o.getClass())) {\r
+                                               value = (X) Utils.convert(o, byte[].class);\r
                                        } else {\r
                                                value = (X) o;\r
                                        }\r
index 456d0f49f04fb6f275d27e97f506c253cac20f98..a38ac51a1242c2f7fb8bddd6b9217f4159077bd6 100644 (file)
@@ -27,7 +27,9 @@ import java.util.IdentityHashMap;
 import java.util.List;\r
 import java.util.Map;\r
 \r
+import com.iciql.Iciql.EnumType;\r
 import com.iciql.Iciql.IQColumn;\r
+import com.iciql.Iciql.IQEnum;\r
 import com.iciql.Iciql.IQIndex;\r
 import com.iciql.Iciql.IQIndexes;\r
 import com.iciql.Iciql.IQSchema;\r
@@ -74,6 +76,7 @@ class TableDefinition<T> {
                boolean trimString;\r
                boolean allowNull;\r
                String defaultValue;\r
+               EnumType enumType;\r
 \r
                Object getValue(Object obj) {\r
                        try {\r
@@ -264,6 +267,7 @@ class TableDefinition<T> {
                        int maxLength = 0;\r
                        boolean trimString = false;\r
                        boolean allowNull = true;\r
+                       EnumType enumType = null;\r
                        String defaultValue = "";\r
                        boolean hasAnnotation = f.isAnnotationPresent(IQColumn.class);\r
                        if (hasAnnotation) {\r
@@ -278,6 +282,21 @@ class TableDefinition<T> {
                                allowNull = col.allowNull();\r
                                defaultValue = col.defaultValue();\r
                        }\r
+\r
+                       // configure Java -> SQL enum mapping\r
+                       if (f.getType().isEnum()) {\r
+                               if (f.getType().isAnnotationPresent(IQEnum.class)) {\r
+                                       // enum definition is annotated for all instances\r
+                                       IQEnum iqenum = f.getType().getAnnotation(IQEnum.class);\r
+                                       enumType = iqenum.value();\r
+                               }\r
+                               if (f.isAnnotationPresent(IQEnum.class)) {\r
+                                       // this instance of the enum is annotated\r
+                                       IQEnum iqenum = f.getAnnotation(IQEnum.class);\r
+                                       enumType = iqenum.value();\r
+                               }\r
+                       }\r
+\r
                        boolean isPublic = Modifier.isPublic(f.getModifiers());\r
                        boolean reflectiveMatch = isPublic && !byAnnotationsOnly;\r
                        if (reflectiveMatch || hasAnnotation) {\r
@@ -290,6 +309,7 @@ class TableDefinition<T> {
                                fieldDef.trimString = trimString;\r
                                fieldDef.allowNull = allowNull;\r
                                fieldDef.defaultValue = defaultValue;\r
+                               fieldDef.enumType = enumType;\r
                                fieldDef.dataType = ModelUtils.getDataType(fieldDef, strictTypeMapping);\r
                                fields.add(fieldDef);\r
                        }\r
@@ -306,10 +326,26 @@ class TableDefinition<T> {
        }\r
 \r
        /**\r
-        * Optionally truncates strings to the maximum length\r
+        * Optionally truncates strings to the maximum length and converts\r
+        * java.lang.Enum types to Strings or Integers.\r
         */\r
        private Object getValue(Object obj, FieldDefinition field) {\r
                Object value = field.getValue(obj);\r
+               if (field.enumType != null) {\r
+                       // convert enumeration to INT or STRING\r
+                       Enum<?> iqenum = (Enum<?>) value;\r
+                       switch (field.enumType) {\r
+                       case STRING:\r
+                               if (field.trimString && field.maxLength > 0) {\r
+                                       if (iqenum.name().length() > field.maxLength) {\r
+                                               return iqenum.name().substring(0, field.maxLength);\r
+                                       }\r
+                               }\r
+                               return iqenum.name();\r
+                       case ORDINAL:\r
+                               return iqenum.ordinal();                        \r
+                       }\r
+               }\r
                if (field.trimString && field.maxLength > 0) {\r
                        if (value instanceof String) {\r
                                // clip strings\r
index 8e537b4addd2ad09fc513aa822765057dc5952d0..879e23a25c8a813f25ab64df9066bd24651a2fd8 100644 (file)
@@ -324,8 +324,12 @@ public class TableInspector {
                        clazz = Object.class;
                        sb.append("// unsupported type " + col.type);
                } else {
+                       // Imports
+                       // don't import byte []
+                       if (!clazz.equals(byte[].class)) {
+                               imports.add(clazz.getCanonicalName());
+                       }
                        // @IQColumn
-                       imports.add(clazz.getCanonicalName());
                        sb.append('@').append(IQColumn.class.getSimpleName());
 
                        // IQColumn annotation parameters
index 0686defad8f6cee03a05d885440ab38a67ed31a7..4ff5e68375aeff4806ae8b26b781158464f08b24 100644 (file)
@@ -189,6 +189,10 @@ public class BuildSite {
                                                String[] kv = token.split("=", 2);\r
                                                content = content.replace(kv[0], kv[1]);\r
                                        }\r
+                                       for (String token : params.regex) {\r
+                                               String[] kv = token.split("!!!", 2);\r
+                                               content = content.replaceAll(kv[0], kv[1]);\r
+                                       }\r
 \r
                                        OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(new File(destinationFolder,\r
                                                        fileName)), Charset.forName("UTF-8"));\r
@@ -315,6 +319,9 @@ public class BuildSite {
 \r
                @Parameter(names = { "--nomarkdown" }, description = "%STARTTOKEN%:%ENDTOKEN%", required = false)\r
                public List<String> nomarkdown = new ArrayList<String>();\r
+               \r
+               @Parameter(names = { "--regex" }, description = "searchPattern!!!replacePattern", required = false)\r
+               public List<String> regex = new ArrayList<String>();\r
 \r
        }\r
 }\r
index 3a600fa37f880a9308a413ab0cbd65b3a62f0814..39875fbb3d6f9de9f1716ca90ff76fd0652e30fe 100644 (file)
 \r
 package com.iciql.util;\r
 \r
+import java.io.ByteArrayOutputStream;\r
 import java.io.IOException;\r
+import java.io.InputStream;\r
 import java.io.Reader;\r
 import java.io.StringWriter;\r
 import java.lang.reflect.Constructor;\r
 import java.math.BigDecimal;\r
 import java.math.BigInteger;\r
+import java.sql.Blob;\r
 import java.sql.Clob;\r
 import java.util.ArrayList;\r
 import java.util.Collection;\r
@@ -148,6 +151,12 @@ public class Utils {
                        return (T) new java.sql.Timestamp(COUNTER.getAndIncrement());\r
                } else if (clazz == java.util.Date.class) {\r
                        return (T) new java.util.Date(COUNTER.getAndIncrement());\r
+               } else if (clazz == byte[].class) {\r
+                       return (T) new byte[0];\r
+               } else if (clazz.isEnum()) {\r
+                       // enums can not be instantiated reflectively\r
+                       // return first constant as reference\r
+                       return clazz.getEnumConstants()[0];\r
                } else if (clazz == List.class) {\r
                        return (T) new ArrayList();\r
                }\r
@@ -200,6 +209,11 @@ public class Utils {
                if (targetType.isAssignableFrom(currentType)) {\r
                        return o;\r
                }\r
+               // convert enum\r
+               if (targetType.isEnum()) {\r
+                       return convertEnum(o, targetType);\r
+               }\r
+               // convert from CLOB/TEXT/VARCHAR to String\r
                if (targetType == String.class) {\r
                        if (Clob.class.isAssignableFrom(currentType)) {\r
                                Clob c = (Clob) o;\r
@@ -212,6 +226,8 @@ public class Utils {
                        }\r
                        return o.toString();\r
                }\r
+\r
+               // convert from number to number\r
                if (Number.class.isAssignableFrom(currentType)) {\r
                        Number n = (Number) o;\r
                        if (targetType == Byte.class) {\r
@@ -228,6 +244,67 @@ public class Utils {
                                return n.floatValue();\r
                        }\r
                }\r
+\r
+               // convert from BLOB\r
+               if (targetType == byte[].class) {\r
+                       if (Blob.class.isAssignableFrom(currentType)) {\r
+                               Blob b = (Blob) o;\r
+                               try {\r
+                                       InputStream is = b.getBinaryStream();\r
+                                       return readBlobAndClose(is, -1);\r
+                               } catch (Exception e) {\r
+                                       throw new IciqlException("Error converting BLOB to byte[]: " + e.toString(), e);\r
+                               }\r
+                       }\r
+               }\r
+\r
+               throw new IciqlException("Can not convert the value " + o + " from " + currentType + " to "\r
+                               + targetType);\r
+       }\r
+       \r
+       private static Object convertEnum(Object o, Class<?> targetType) {\r
+               if (o == null) {\r
+                       return null;\r
+               }\r
+               Class<?> currentType = o.getClass();\r
+               // convert from VARCHAR/TEXT/INT to Enum\r
+               Enum<?>[] values = (Enum[]) targetType.getEnumConstants();\r
+               if (Clob.class.isAssignableFrom(currentType)) {\r
+                       // TEXT/CLOB field\r
+                       Clob c = (Clob) o;\r
+                       String name = null;\r
+                       try {\r
+                               Reader r = c.getCharacterStream();\r
+                               name = readStringAndClose(r, -1);\r
+                       } catch (Exception e) {\r
+                               throw new IciqlException("Error converting CLOB to String: " + e.toString(), e);\r
+                       }\r
+\r
+                       // find name match\r
+                       for (Enum<?> value : values) {\r
+                               if (value.name().equalsIgnoreCase(name)) {\r
+                                       return value;\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
+                               }\r
+                       }\r
+               } else if (Number.class.isAssignableFrom(currentType)) {\r
+                       // INT field\r
+                       int n = ((Number) o).intValue();\r
+\r
+                       // ORDINAL mapping\r
+                       for (Enum<?> value : values) {\r
+                               if (value.ordinal() == n) {\r
+                                       return value;\r
+                               }\r
+                       }\r
+               }\r
                throw new IciqlException("Can not convert the value " + o + " from " + currentType + " to "\r
                                + targetType);\r
        }\r
@@ -264,4 +341,38 @@ public class Utils {
                        in.close();\r
                }\r
        }\r
+\r
+       /**\r
+        * Read a number of bytes from a stream and close it.\r
+        * \r
+        * @param in\r
+        *            the stream\r
+        * @param length\r
+        *            the maximum number of bytes to read, or -1 to read until the\r
+        *            end of file\r
+        * @return the string read\r
+        */\r
+       public static byte[] readBlobAndClose(InputStream in, int length) throws IOException {\r
+               try {\r
+                       if (length <= 0) {\r
+                               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
+                       byte[] buff = new byte[block];\r
+                       while (length > 0) {\r
+                               int len = Math.min(block, length);\r
+                               len = in.read(buff, 0, len);\r
+                               if (len < 0) {\r
+                                       break;\r
+                               }\r
+                               out.write(buff, 0, len);\r
+                               length -= len;\r
+                       }\r
+                       return out.toByteArray();\r
+               } finally {\r
+                       in.close();\r
+               }\r
+       }\r
 }\r
index 851da92da5a061413f842bd4ae0cdbd1318c1efc..bafc3e00bd0af911ac6bf26e5fd8a0c77679e941 100644 (file)
@@ -115,7 +115,7 @@ public class ModelsTest {
                                true);
                assertEquals(1, models.size());
                // a poor test, but a start
-               assertEquals(1564, models.get(0).length());
+               assertEquals(1838, models.get(0).length());
        }
 
        @Test
index 6b8d42014120e39bb14ad6ad4965dba15a76a0f1..caf07c7a19d22231a433f46542946486417a81a5 100644 (file)
@@ -31,8 +31,7 @@ import com.iciql.Iciql.IndexType;
  */
 
 @IQTable(name = "AnnotatedProduct", primaryKey = "id")
-@IQIndexes({ @IQIndex({ "name", "cat" }),
-               @IQIndex(name = "nameidx", type = IndexType.HASH, value = "name") })
+@IQIndexes({ @IQIndex({ "name", "cat" }), @IQIndex(name = "nameidx", type = IndexType.HASH, value = "name") })
 public class ProductAnnotationOnly {
 
        @IQColumn(autoIncrement = true)
index 66c25d49cc379bb9bcb42f870d4a2b4384d7538d..bb5ecc6904d5cd4a5c3eaf7e69b4ecdf6ed91bf7 100644 (file)
@@ -21,7 +21,9 @@ import java.math.BigDecimal;
 import java.util.List;
 import java.util.Random;
 
+import com.iciql.Iciql.EnumType;
 import com.iciql.Iciql.IQColumn;
+import com.iciql.Iciql.IQEnum;
 import com.iciql.Iciql.IQIndex;
 import com.iciql.Iciql.IQIndexes;
 import com.iciql.Iciql.IQTable;
@@ -39,6 +41,29 @@ public class SupportedTypes {
 
        public static final SupportedTypes SAMPLE = new SupportedTypes();
 
+       /**
+        * Test of plain enumeration.
+        * 
+        * Each field declaraton of this enum must specify a mapping strategy.
+        */
+       public enum Flower {
+               ROSE, TULIP, MUM, PETUNIA, MARIGOLD, DAFFODIL;
+       }
+
+       /**
+        * Test of @IQEnum annotated enumeration.
+        * This strategy is the default strategy for all fields of the Tree enum.
+        * 
+        * Individual Tree field declarations can override this strategy by
+        * specifying a different @IQEnum annotation.
+        * 
+        * Here ORDINAL specifies that this enum will be mapped to an INT column.
+        */
+       @IQEnum(EnumType.ORDINAL)
+       public enum Tree {
+               PINE, OAK, BIRCH, WALNUT, MAPLE;
+       }
+
        @IQColumn(primaryKey = true, autoIncrement = true)
        public Integer id;
 
@@ -81,6 +106,22 @@ public class SupportedTypes {
        @IQColumn
        private java.sql.Timestamp mySqlTimestamp;
 
+       @IQColumn
+       private byte[] myBlob;
+
+       @IQEnum(EnumType.STRING)
+       @IQColumn(trimString = true, maxLength = 25)
+       private Flower myFavoriteFlower;
+
+       @IQEnum(EnumType.ORDINAL)
+       @IQColumn
+       private Flower myOtherFavoriteFlower;
+
+       @IQColumn(maxLength = 25)
+       // @IQEnum is set on the enumeration definition and is shared
+       // by all uses of Tree as an @IQColumn
+       private Tree myFavoriteTree;
+
        public static List<SupportedTypes> createList() {
                List<SupportedTypes> list = Utils.newArrayList();
                for (int i = 0; i < 10; i++) {
@@ -105,6 +146,10 @@ public class SupportedTypes {
                s.mySqlDate = new java.sql.Date(rand.nextLong());
                s.mySqlTime = new java.sql.Time(rand.nextLong());
                s.mySqlTimestamp = new java.sql.Timestamp(rand.nextLong());
+               s.myBlob = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+               s.myFavoriteFlower = Flower.MUM;
+               s.myOtherFavoriteFlower = Flower.MARIGOLD;
+               s.myFavoriteTree = Tree.BIRCH;
                return s;
        }
 
@@ -123,9 +168,28 @@ public class SupportedTypes {
                same &= mySqlDate.toString().equals(s.mySqlDate.toString());
                same &= mySqlTime.toString().equals(s.mySqlTime.toString());
                same &= myString.equals(s.myString);
+               same &= compare(myBlob, s.myBlob);
+               same &= myFavoriteFlower.equals(s.myFavoriteFlower);
+               same &= myOtherFavoriteFlower.equals(s.myOtherFavoriteFlower);
+               same &= myFavoriteTree.equals(s.myFavoriteTree);
                return same;
        }
 
+       private boolean compare(byte[] a, byte[] b) {
+               if (b == null) {
+                       return false;
+               }
+               if (a.length != b.length) {
+                       return false;
+               }
+               for (int i = 0; i < a.length; i++) {
+                       if (a[i] != b[i]) {
+                               return false;
+                       }
+               }
+               return true;
+       }
+
        /**
         * This class demonstrates the table upgrade.
         */