]> source.dussan.org Git - iciql.git/commitdiff
Support data type adapters
authorJames Moger <james.moger@gitblit.com>
Wed, 29 Oct 2014 21:12:14 +0000 (17:12 -0400)
committerJames Moger <james.moger@gitblit.com>
Wed, 29 Oct 2014 21:12:14 +0000 (17:12 -0400)
This allows custom types to be (de)serialized into a standard JDBC type or
to support db-specific data types, like the Postgres json and xml types.

19 files changed:
releases.moxie
src/main/java/com/iciql/Db.java
src/main/java/com/iciql/Define.java
src/main/java/com/iciql/Iciql.java
src/main/java/com/iciql/JavaSerializationTypeAdapter.java [new file with mode: 0644]
src/main/java/com/iciql/Query.java
src/main/java/com/iciql/SQLDialect.java
src/main/java/com/iciql/SQLDialectDefault.java
src/main/java/com/iciql/SQLDialectH2.java
src/main/java/com/iciql/SQLDialectHSQL.java
src/main/java/com/iciql/SQLDialectMySQL.java
src/main/java/com/iciql/SQLDialectPostgreSQL.java
src/main/java/com/iciql/SQLStatement.java
src/main/java/com/iciql/TableDefinition.java
src/site/jaqu_comparison.mkd
src/site/model_classes.mkd
src/test/java/com/iciql/test/DataTypeAdapterTest.java [new file with mode: 0644]
src/test/java/com/iciql/test/IciqlSuite.java
src/test/java/com/iciql/test/models/SupportedTypes.java

index c0e2c5093763def150d8c9929f61ceb8da8b3071..887eb08657c732ecb806920061bc04cd230e316a 100644 (file)
@@ -11,9 +11,14 @@ r22: {
     security: ~
     fixes: ~
     changes: ~
-    additions: ~
+    additions:
+    - Support for specifying custom data type adapters in @IQColumn and Define.typeAdapter()
+    - Added com.iciql.SQLDialectPostgreSQL.JsonStringAdapter
+    - Added com.iciql.SQLDialectPostgreSQL.XmlStringAdapter
+    - Added com.iciql.JavaSerializationTypeAdapter to (de)serialize objects into a BLOB column
     dependencyChanges: ~
-    contributors: ~
+    contributors:
+    - James Moger
 }
 
 #
index ecd373c9005d5a5d61b4a33b12e7bb6c6cdab745..179b18d54eb173f22d95ab784ba6a7a3edc6c9c8 100644 (file)
@@ -62,7 +62,7 @@ public class Db {
        private static final Map<Object, Token> TOKENS;\r
 \r
        private static final Map<String, Class<? extends SQLDialect>> DIALECTS;\r
-       \r
+\r
        private final Connection conn;\r
        private final Map<Class<?>, TableDefinition<?>> classMap = Collections\r
                        .synchronizedMap(new HashMap<Class<?>, TableDefinition<?>>());\r
@@ -72,7 +72,7 @@ public class Db {
 \r
        private boolean skipCreate;\r
        private boolean autoSavePoint = true;\r
-       \r
+\r
        static {\r
                TOKENS = Collections.synchronizedMap(new WeakIdentityHashMap<Object, Token>());\r
                DIALECTS = Collections.synchronizedMap(new HashMap<String, Class<? extends SQLDialect>>());\r
@@ -104,7 +104,7 @@ public class Db {
        /**\r
         * Register a new/custom dialect class. You can use this method to replace\r
         * any existing dialect or to add a new one.\r
-        * \r
+        *\r
         * @param token\r
         *            the fully qualified name of the connection class or the\r
         *            expected result of DatabaseMetaData.getDatabaseProductName()\r
@@ -146,7 +146,7 @@ public class Db {
                        throw new IciqlException(e);\r
                }\r
        }\r
-       \r
+\r
        public static Db open(String url) {\r
                try {\r
                        Connection conn = JdbcUtils.getConnection(null, url, null, null);\r
@@ -164,7 +164,7 @@ public class Db {
                        throw new IciqlException(e);\r
                }\r
        }\r
-       \r
+\r
        public static Db open(String url, String user, char[] password) {\r
                try {\r
                        Connection conn = JdbcUtils.getConnection(null, url, user, password == null ? null : new String(password));\r
@@ -177,7 +177,7 @@ public class Db {
        /**\r
         * Create a new database instance using a data source. This method is fast,\r
         * so that you can always call open() / close() on usage.\r
-        * \r
+        *\r
         * @param ds\r
         *            the data source\r
         * @return the database instance.\r
@@ -194,8 +194,8 @@ public class Db {
                return new Db(conn);\r
        }\r
 \r
-       \r
-       \r
+\r
+\r
        /**\r
         * Convenience function to avoid import statements in application code.\r
         */\r
@@ -227,7 +227,7 @@ public class Db {
         * Merge INSERTS if the record does not exist or UPDATES the record if it\r
         * does exist. Not all databases support MERGE and the syntax varies with\r
         * the database.\r
-        * \r
+        *\r
         * If the database does not support a MERGE syntax the dialect can try to\r
         * simulate a merge by implementing:\r
         * <p>\r
@@ -239,7 +239,7 @@ public class Db {
         * See the Derby dialect for an implementation of this technique.\r
         * <p>\r
         * If the dialect does not support merge an IciqlException will be thrown.\r
-        * \r
+        *\r
         * @param t\r
         */\r
        public <T> void merge(T t) {\r
@@ -324,7 +324,7 @@ public class Db {
                        int[] columns = def.mapColumns(wildcardSelect, rs);\r
                        while (rs.next()) {\r
                                T item = Utils.newObject(modelClass);\r
-                               def.readRow(item, rs, columns);\r
+                               def.readRow(dialect, item, rs, columns);\r
                                result.add(item);\r
                        }\r
                } catch (SQLException e) {\r
@@ -417,7 +417,7 @@ public class Db {
                if (def == null) {\r
                        upgradeDb();\r
                        def = new TableDefinition<T>(clazz);\r
-                       def.mapFields();\r
+                       def.mapFields(this);\r
                        classMap.put(clazz, def);\r
                        if (Iciql.class.isAssignableFrom(clazz)) {\r
                                T t = instance(clazz);\r
@@ -437,7 +437,7 @@ public class Db {
                }\r
                return def;\r
        }\r
-       \r
+\r
        <T> boolean hasCreated(Class<T> clazz) {\r
                return upgradeChecked.contains(clazz);\r
        }\r
@@ -567,7 +567,7 @@ public class Db {
                        throw IciqlException.fromSQL(sql, e);\r
                }\r
        }\r
-       \r
+\r
        Savepoint prepareSavepoint() {\r
                // don't change auto-commit mode.\r
                // don't create save point.\r
@@ -580,13 +580,13 @@ public class Db {
                        conn.setAutoCommit(false);\r
                        savepoint = conn.setSavepoint();\r
                } catch (SQLFeatureNotSupportedException e) {\r
-                       // jdbc driver does not support save points                     \r
+                       // jdbc driver does not support save points\r
                } catch (SQLException e) {\r
                        throw new IciqlException(e, "Could not create save point");\r
                }\r
                return savepoint;\r
        }\r
-       \r
+\r
        void commit(Savepoint savepoint) {\r
                if (savepoint != null) {\r
                        try {\r
@@ -597,7 +597,7 @@ public class Db {
                        }\r
                }\r
        }\r
-       \r
+\r
        void rollback(Savepoint savepoint) {\r
                if (savepoint != null) {\r
                        try {\r
@@ -616,13 +616,13 @@ public class Db {
 \r
        /**\r
         * Run a SQL query directly against the database.\r
-        * \r
+        *\r
         * Be sure to close the ResultSet with\r
-        * \r
+        *\r
         * <pre>\r
         * JdbcUtils.closeSilently(rs, true);\r
         * </pre>\r
-        * \r
+        *\r
         * @param sql\r
         *            the SQL statement\r
         * @param args\r
@@ -635,13 +635,13 @@ public class Db {
 \r
        /**\r
         * Run a SQL query directly against the database.\r
-        * \r
+        *\r
         * Be sure to close the ResultSet with\r
-        * \r
+        *\r
         * <pre>\r
         * JdbcUtils.closeSilently(rs, true);\r
         * </pre>\r
-        * \r
+        *\r
         * @param sql\r
         *            the SQL statement\r
         * @param args\r
@@ -668,7 +668,7 @@ public class Db {
        /**\r
         * Run a SQL query directly against the database and map the results to the\r
         * model class.\r
-        * \r
+        *\r
         * @param modelClass\r
         *            the model class to bind the query ResultSet rows into.\r
         * @param sql\r
@@ -682,7 +682,7 @@ public class Db {
        /**\r
         * Run a SQL query directly against the database and map the results to the\r
         * model class.\r
-        * \r
+        *\r
         * @param modelClass\r
         *            the model class to bind the query ResultSet rows into.\r
         * @param sql\r
@@ -714,7 +714,7 @@ public class Db {
 \r
        /**\r
         * Run a SQL statement directly against the database.\r
-        * \r
+        *\r
         * @param sql\r
         *            the SQL statement\r
         * @return the update count\r
@@ -727,14 +727,14 @@ public class Db {
                                stat = conn.createStatement();\r
                                updateCount = stat.executeUpdate(sql);\r
                        } else {\r
-                               PreparedStatement ps = conn.prepareStatement(sql);                              \r
+                               PreparedStatement ps = conn.prepareStatement(sql);\r
                                int i = 1;\r
                                for (Object arg : args) {\r
                                        ps.setObject(i++, arg);\r
                                }\r
                                updateCount = ps.executeUpdate();\r
                                stat = ps;\r
-                       }                       \r
+                       }\r
                        return updateCount;\r
                } catch (SQLException e) {\r
                        throw new IciqlException(e);\r
@@ -756,7 +756,7 @@ public class Db {
        public boolean getSkipCreate() {\r
                return this.skipCreate;\r
        }\r
-       \r
+\r
        /**\r
         * Allow to enable/disable usage of save point.\r
         * For advanced user wanting to gain full control of transactions.\r
@@ -770,5 +770,5 @@ public class Db {
        public boolean getAutoSavePoint() {\r
                return this.autoSavePoint;\r
        }\r
-       \r
+\r
 }\r
index 1810a4b45f84602227cbdc067a5a8599d8158ee8..b16ee6ec9a596afe363bd73711fa359f20b382b3 100644 (file)
@@ -18,6 +18,7 @@
 \r
 package com.iciql;\r
 \r
+import com.iciql.Iciql.DataTypeAdapter;\r
 import com.iciql.Iciql.IndexType;\r
 \r
 /**\r
@@ -49,7 +50,7 @@ public class Define {
                checkInDefine();\r
                currentTableDefinition.defineConstraintUnique(name, columns);\r
        }\r
-       \r
+\r
        /*\r
         * The variable argument type Object can't be used twice :-)\r
         */\r
@@ -59,12 +60,12 @@ public class Define {
 //             checkInDefine();\r
 //             currentTableDefinition.defineForeignKey(name, columns, refTableName, Columns, deleteType, updateType, deferrabilityType);\r
 //     }\r
-       \r
+\r
        public static void primaryKey(Object... columns) {\r
                checkInDefine();\r
                currentTableDefinition.definePrimaryKey(columns);\r
        }\r
-       \r
+\r
        public static void schemaName(String schemaName) {\r
                checkInDefine();\r
                currentTableDefinition.defineSchemaName(schemaName);\r
@@ -79,7 +80,7 @@ public class Define {
                checkInDefine();\r
                currentTableDefinition.defineViewTableName(viewTableName);\r
        }\r
-       \r
+\r
        public static void memoryTable() {\r
                checkInDefine();\r
                currentTableDefinition.defineMemoryTable();\r
@@ -104,17 +105,17 @@ public class Define {
                checkInDefine();\r
                currentTableDefinition.defineScale(column, scale);\r
        }\r
-       \r
+\r
        public static void trim(Object column) {\r
                checkInDefine();\r
                currentTableDefinition.defineTrim(column);\r
        }\r
-       \r
+\r
        public static void nullable(Object column, boolean isNullable) {\r
                checkInDefine();\r
                currentTableDefinition.defineNullable(column, isNullable);\r
        }\r
-       \r
+\r
        public static void defaultValue(Object column, String defaultValue) {\r
                checkInDefine();\r
                currentTableDefinition.defineDefaultValue(column, defaultValue);\r
@@ -125,6 +126,11 @@ public class Define {
                currentTableDefinition.defineConstraint(column, constraint);\r
        }\r
 \r
+       public static void typeAdapter(Object column, Class<? extends DataTypeAdapter<?>> typeAdapter) {\r
+               checkInDefine();\r
+               currentTableDefinition.defineTypeAdapter(column, typeAdapter);\r
+       }\r
+\r
        static synchronized <T> void define(TableDefinition<T> tableDefinition, Iciql table) {\r
                currentTableDefinition = tableDefinition;\r
                currentTable = table;\r
index 521e46066e17957a00be89da1c72cf5efa5bd941..05cceebdaf313f552e48e4762acfcd01e8cba153 100644 (file)
@@ -657,6 +657,14 @@ public interface Iciql {
                 */\r
                String defaultValue() default "";\r
 \r
+               /**\r
+                * Allows specifying a custom data type adapter.\r
+                * <p>\r
+                * For example, you might use this option to map a Postgres JSON column.\r
+                * </p>\r
+                */\r
+               Class<? extends DataTypeAdapter<?>> typeAdapter() default StandardJDBCTypeAdapter.class;\r
+\r
        }\r
 \r
        /**\r
@@ -731,4 +739,74 @@ public interface Iciql {
         * and the table name.\r
         */\r
        void defineIQ();\r
+\r
+       /**\r
+        * Interface to allow implementations of custom data type adapters for supporting\r
+        * database-specific data types, like the Postgres 'json' or 'xml' types,\r
+        * or for supporting other object serialization schemes.\r
+        * <p><b>NOTE:</b> Data type adapters are not thread-safe!</p>\r
+        *\r
+        * @param <T>\r
+        */\r
+       public interface DataTypeAdapter<T> {\r
+\r
+               /**\r
+                * The SQL data type for this adapter.\r
+                *\r
+                * @return the SQL data type\r
+                */\r
+               String getDataType();\r
+\r
+               /**\r
+                * The Java domain type for this adapter.\r
+                *\r
+                * @return the Java domain type\r
+                */\r
+               Class<T> getJavaType();\r
+\r
+               /**\r
+                * Serializes your Java object into a JDBC object.\r
+                *\r
+                * @param value\r
+                * @return a JDBC object\r
+                */\r
+               Object serialize(T value);\r
+\r
+               /**\r
+                * Deserializes a JDBC object into your Java object.\r
+                *\r
+                * @param value\r
+                * @return the Java object\r
+                */\r
+               T deserialize(Object value);\r
+\r
+       }\r
+\r
+       /**\r
+        * The standard type adapter allows iciql to use it's internal utility convert functions\r
+        * to handle the standard JDBC types.\r
+        */\r
+       public final static class StandardJDBCTypeAdapter implements DataTypeAdapter<Object> {\r
+\r
+               @Override\r
+               public String getDataType() {\r
+                       throw new RuntimeException("This adapter is for all standard JDBC types.");\r
+               }\r
+\r
+               @Override\r
+               public Class<Object> getJavaType() {\r
+                       throw new RuntimeException("This adapter is for all standard JDBC types.");\r
+               }\r
+\r
+               @Override\r
+               public Object serialize(Object value) {\r
+                       return value;\r
+               }\r
+\r
+               @Override\r
+               public Object deserialize(Object value) {\r
+                       return value;\r
+               }\r
+\r
+       }\r
 }\r
diff --git a/src/main/java/com/iciql/JavaSerializationTypeAdapter.java b/src/main/java/com/iciql/JavaSerializationTypeAdapter.java
new file mode 100644 (file)
index 0000000..e38e0f8
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2014 James Moger.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.iciql;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.sql.Blob;
+import java.sql.SQLException;
+
+import com.iciql.Iciql.DataTypeAdapter;
+
+/**
+ * Base class for inserting/retrieving a Java Object as a BLOB field using Java Serialization.
+ * <p>You use this by creating a subclass which defines your object class.</p>
+ * <pre>
+ * public class CustomObjectAdapter extends JavaSerializationTypeAdapter&lt;CustomObject&gt; {
+ *
+ *    public Class&lt;CustomObject&gt; getJavaType() {
+ *        return CustomObject.class;
+ *    }
+ * }
+ * </pre>
+ * @param <T>
+ */
+public abstract class JavaSerializationTypeAdapter<T> implements DataTypeAdapter<T> {
+
+       @Override
+       public final String getDataType() {
+               return "BLOB";
+       }
+
+       @Override
+       public final Object serialize(T value) {
+               ByteArrayOutputStream os = new ByteArrayOutputStream();
+               try {
+                       new ObjectOutputStream(os).writeObject(value);
+                       return os.toByteArray();
+               } catch (IOException e) {
+                       throw new IciqlException(e);
+               } finally {
+                       try {
+                               os.close();
+                       } catch (IOException e) {
+                               throw new IciqlException (e);
+                       }
+               }
+       }
+
+       @SuppressWarnings("unchecked")
+       @Override
+       public final T deserialize(Object value) {
+               InputStream is = null;
+               if (value instanceof Blob) {
+                       Blob blob = (Blob) value;
+                       try {
+                               is = blob.getBinaryStream();
+                       } catch (SQLException e) {
+                               throw new IciqlException(e);
+                       }
+               } else if (value instanceof byte[]) {
+                       byte [] bytes = (byte []) value;
+                       is = new ByteArrayInputStream(bytes);
+               }
+
+               try {
+                       T object = (T) new ObjectInputStream(is).readObject();
+                       return object;
+               } catch (Exception e) {
+                       throw new IciqlException(e);
+               } finally {
+                       if (is != null) {
+                               try {
+                                       is.close();
+                               } catch (IOException e) {
+                                       throw new IciqlException (e);
+                               }
+                       }
+               }
+       }
+}
index f22215cebd19362304b227ee351e56d28f05da75..7c5c985153931bbcde73da5a07c14e013cc5ceda 100644 (file)
@@ -28,9 +28,9 @@ import java.util.HashMap;
 import java.util.IdentityHashMap;\r
 import java.util.List;\r
 \r
+import com.iciql.Iciql.EnumType;\r
 import com.iciql.NestedConditions.And;\r
 import com.iciql.NestedConditions.Or;\r
-import com.iciql.Iciql.EnumType;\r
 import com.iciql.bytecode.ClassReader;\r
 import com.iciql.util.IciqlLogger;\r
 import com.iciql.util.JdbcUtils;\r
@@ -253,7 +253,7 @@ public class Query<T> {
                        int[] columns = def.mapColumns(false, rs);\r
                        while (rs.next()) {\r
                                T item = from.newObject();\r
-                               def.readRow(item, rs, columns);\r
+                               def.readRow(db.getDialect(), item, rs, columns);\r
                                result.add(item);\r
                        }\r
                } catch (SQLException e) {\r
@@ -406,7 +406,7 @@ public class Query<T> {
                        int[] columns = def.mapColumns(false, rs);\r
                        while (rs.next()) {\r
                                X row = Utils.newObject(clazz);\r
-                               def.readRow(row, rs, columns);\r
+                               def.readRow(db.getDialect(), row, rs, columns);\r
                                result.add(row);\r
                        }\r
                } catch (SQLException e) {\r
@@ -841,13 +841,19 @@ public class Query<T> {
        }\r
 \r
        private void addParameter(SQLStatement stat, Object alias, Object value) {\r
-               if (alias != null && value.getClass().isEnum()) {\r
-                       SelectColumn<T> col = getColumnByReference(alias);\r
+               SelectColumn<T> col = getColumnByReference(alias);\r
+               if (col != null && value.getClass().isEnum()) {\r
+                       // enum\r
                        EnumType type = col.getFieldDefinition().enumType;\r
                        Enum<?> anEnum = (Enum<?>) value;\r
                        Object y = Utils.convertEnum(anEnum, type);\r
                        stat.addParameter(y);\r
+               } else if (col != null) {\r
+                       // object\r
+                       Object parameter = db.getDialect().serialize(value, col.getFieldDefinition().typeAdapter);\r
+                       stat.addParameter(parameter);\r
                } else {\r
+                       // primitive\r
                        stat.addParameter(value);\r
                }\r
        }\r
index f62168ef7b003407a204e78b2319de75e1434a10..8937baf2b765025f8ae2954d2a17d3e594389065 100644 (file)
@@ -20,6 +20,7 @@ package com.iciql;
 
 import java.sql.DatabaseMetaData;
 
+import com.iciql.Iciql.DataTypeAdapter;
 import com.iciql.TableDefinition.ConstraintForeignKeyDefinition;
 import com.iciql.TableDefinition.ConstraintUniqueDefinition;
 import com.iciql.TableDefinition.IndexDefinition;
@@ -30,9 +31,35 @@ import com.iciql.TableDefinition.IndexDefinition;
  */
 public interface SQLDialect {
 
+       /**
+        * Returns the registered instance of the type adapter.
+        *
+        * @param typeAdapter
+        * @return the type adapter instance
+        */
+       DataTypeAdapter<?> getTypeAdapter(Class<? extends DataTypeAdapter<?>> typeAdapter);
+
+       /**
+        * Serialize the Java object into a type or format that the database will accept.
+        *
+        * @param value
+        * @param typeAdapter
+        * @return the serialized object
+        */
+       <T> Object serialize(T value, Class<? extends DataTypeAdapter<?>> typeAdapter);
+
+       /**
+        * Deserialize the object received from the database into a Java type.
+        *
+        * @param value
+        * @param typeAdapter
+        * @return the deserialized object
+        */
+       Object deserialize(Object value, Class<? extends DataTypeAdapter<?>> typeAdapter);
+
        /**
         * Configure the dialect from the database metadata.
-        * 
+        *
         * @param databaseName
         * @param data
         */
@@ -40,7 +67,7 @@ public interface SQLDialect {
 
        /**
         * Allows a dialect to substitute an SQL type.
-        * 
+        *
         * @param sqlType
         * @return the dialect-safe type
         */
@@ -48,7 +75,7 @@ public interface SQLDialect {
 
        /**
         * Returns a properly formatted table name for the dialect.
-        * 
+        *
         * @param schemaName
         *            the schema name, or null for no schema
         * @param tableName
@@ -59,7 +86,7 @@ public interface SQLDialect {
 
        /**
         * Returns a properly formatted column name for the dialect.
-        * 
+        *
         * @param name
         *            the column name
         * @return the properly formatted column name
@@ -68,7 +95,7 @@ public interface SQLDialect {
 
        /**
         * Get the CREATE TABLE statement.
-        * 
+        *
         * @param stat
         * @param def
         */
@@ -76,16 +103,16 @@ public interface SQLDialect {
 
        /**
         * Get the DROP TABLE statement.
-        * 
+        *
         * @param stat
         * @param def
         */
        <T> void prepareDropTable(SQLStatement stat, TableDefinition<T> def);
 
-       
+
        /**
         * Get the CREATE VIEW statement.
-        * 
+        *
         * @param stat
         *            return the SQL statement
         * @param def
@@ -95,7 +122,7 @@ public interface SQLDialect {
 
        /**
         * Get the CREATE VIEW statement.
-        * 
+        *
         * @param stat
         *            return the SQL statement
         * @param def
@@ -106,17 +133,17 @@ public interface SQLDialect {
 
        /**
         * Get the DROP VIEW statement.
-        * 
+        *
         * @param stat
         *            return the SQL statement
         * @param def
         *            table definition
         */
        <T> void prepareDropView(SQLStatement stat, TableDefinition<T> def);
-       
+
        /**
         * Get the CREATE INDEX statement.
-        * 
+        *
         * @param stat
         *            return the SQL statement
         * @param schemaName
@@ -130,7 +157,7 @@ public interface SQLDialect {
 
        /**
         * Get the ALTER statement.
-        * 
+        *
         * @param stat
         *            return the SQL statement
         * @param schemaName
@@ -144,7 +171,7 @@ public interface SQLDialect {
 
        /**
         * Get the ALTER statement.
-        * 
+        *
         * @param stat
         *            return the SQL statement
         * @param schemaName
@@ -159,7 +186,7 @@ public interface SQLDialect {
 
        /**
         * Get a MERGE or REPLACE INTO statement.
-        * 
+        *
         * @param stat
         *            return the SQL statement
         * @param schemaName
@@ -176,7 +203,7 @@ public interface SQLDialect {
 
        /**
         * Append "LIMIT limit OFFSET offset" to the SQL statement.
-        * 
+        *
         * @param stat
         *            the statement
         * @param limit
@@ -190,7 +217,7 @@ public interface SQLDialect {
         * Returns the preferred DATETIME class for the database.
         * <p>
         * Either java.util.Date or java.sql.Timestamp
-        * 
+        *
         * @return preferred DATETIME class
         */
        Class<? extends java.util.Date> getDateTimeClass();
@@ -198,9 +225,10 @@ public interface SQLDialect {
        /**
         * When building static string statements this method flattens an object to
         * a string representation suitable for a static string statement.
-        * 
+        *
         * @param o
         * @return the string equivalent of this object
         */
-       String prepareParameter(Object o);
+       String prepareStringParameter(Object o);
+
 }
index e29d7b870210118f13872e8ebfe86d727fad9b5c..77894120776f82bf25984808fd48a5e7237a0454 100644 (file)
@@ -22,9 +22,12 @@ import java.sql.DatabaseMetaData;
 import java.sql.SQLException;\r
 import java.text.MessageFormat;\r
 import java.text.SimpleDateFormat;\r
+import java.util.Map;\r
+import java.util.concurrent.ConcurrentHashMap;\r
 \r
 import com.iciql.Iciql.ConstraintDeleteType;\r
 import com.iciql.Iciql.ConstraintUpdateType;\r
+import com.iciql.Iciql.DataTypeAdapter;\r
 import com.iciql.TableDefinition.ConstraintForeignKeyDefinition;\r
 import com.iciql.TableDefinition.ConstraintUniqueDefinition;\r
 import com.iciql.TableDefinition.FieldDefinition;\r
@@ -32,6 +35,7 @@ import com.iciql.TableDefinition.IndexDefinition;
 import com.iciql.util.IciqlLogger;\r
 import com.iciql.util.StatementBuilder;\r
 import com.iciql.util.StringUtils;\r
+import com.iciql.util.Utils;\r
 \r
 /**\r
  * Default implementation of an SQL dialect.\r
@@ -45,6 +49,11 @@ public class SQLDialectDefault implements SQLDialect {
        int databaseMinorVersion;\r
        String databaseName;\r
        String productVersion;\r
+       Map<Class<? extends DataTypeAdapter<?>>, DataTypeAdapter<?>> typeAdapters;\r
+\r
+       public SQLDialectDefault() {\r
+               typeAdapters = new ConcurrentHashMap<Class<? extends DataTypeAdapter<?>>, DataTypeAdapter<?>>();\r
+       }\r
 \r
        @Override\r
        public String toString() {\r
@@ -305,7 +314,8 @@ public class SQLDialectDefault implements SQLDialect {
                        buff.appendExceptFirst(", ");\r
                        buff.append('?');\r
                        Object value = def.getValue(obj, field);\r
-                       stat.addParameter(value);\r
+                       Object parameter = serialize(value, field.typeAdapter);\r
+                       stat.addParameter(parameter);\r
                }\r
                buff.append(" FROM ");\r
                buff.append(prepareTableName(schemaName, tableName));\r
@@ -316,7 +326,8 @@ public class SQLDialectDefault implements SQLDialect {
                                buff.appendExceptFirst(" AND ");\r
                                buff.append(MessageFormat.format("{0} = ?", prepareColumnName(field.columnName)));\r
                                Object value = def.getValue(obj, field);\r
-                               stat.addParameter(value);\r
+                               Object parameter = serialize(value, field.typeAdapter);\r
+                               stat.addParameter(parameter);\r
                        }\r
                }\r
                buff.append(" HAVING count(*)=0)");\r
@@ -334,7 +345,40 @@ public class SQLDialectDefault implements SQLDialect {
        }\r
 \r
        @Override\r
-       public String prepareParameter(Object o) {\r
+       public DataTypeAdapter<?> getTypeAdapter(Class<? extends DataTypeAdapter<?>> typeAdapter) {\r
+               DataTypeAdapter<?> dtt = typeAdapters.get(typeAdapter);\r
+               if (dtt == null) {\r
+                       dtt = Utils.newObject(typeAdapter);\r
+                       typeAdapters.put(typeAdapter, dtt);\r
+               }\r
+               return dtt;\r
+       }\r
+\r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public <T> Object serialize(T value, Class<? extends DataTypeAdapter<?>> typeAdapter) {\r
+               if (typeAdapter == null) {\r
+                       // pass-through\r
+                       return value;\r
+               }\r
+\r
+               DataTypeAdapter<T> dtt = (DataTypeAdapter<T>) getTypeAdapter(typeAdapter);\r
+               return dtt.serialize(value);\r
+       }\r
+\r
+       @Override\r
+       public Object deserialize(Object value, Class<? extends DataTypeAdapter<?>> typeAdapter) {\r
+               DataTypeAdapter<?> dtt = typeAdapters.get(typeAdapter);\r
+               if (dtt == null) {\r
+                       dtt = Utils.newObject(typeAdapter);\r
+                       typeAdapters.put(typeAdapter, dtt);\r
+               }\r
+\r
+               return dtt.deserialize(value);\r
+       }\r
+\r
+       @Override\r
+       public String prepareStringParameter(Object o) {\r
                if (o instanceof String) {\r
                        return LITERAL + o.toString().replace(LITERAL, "''") + LITERAL;\r
                } else if (o instanceof Character) {\r
index 6b3bab12a488ae5736c19da602b5d34efea18619..2d7d0fd7039518b72d0fa79c1644921a251d1d0f 100644 (file)
@@ -37,7 +37,7 @@ public class SQLDialectH2 extends SQLDialectDefault {
                        return "CREATE CACHED TABLE IF NOT EXISTS";\r
                }\r
        }\r
-       \r
+\r
        @Override\r
        protected <T> String prepareCreateView(TableDefinition<T> def) {\r
                return "CREATE VIEW IF NOT EXISTS";\r
@@ -127,7 +127,8 @@ public class SQLDialectH2 extends SQLDialectDefault {
                        buff.appendExceptFirst(", ");\r
                        buff.append('?');\r
                        Object value = def.getValue(obj, field);\r
-                       stat.addParameter(value);\r
+                       Object parameter = serialize(value, field.typeAdapter);\r
+                       stat.addParameter(parameter);\r
                }\r
                buff.append(')');\r
                stat.setSQL(buff.toString());\r
index 82e6833e3a8edd98eb0221b46711992b40e2efa0..8b05ca4b7f6ae1eb6af0dcbf462b778a5675fb69 100644 (file)
@@ -38,7 +38,7 @@ public class SQLDialectHSQL extends SQLDialectDefault {
                        return "CREATE CACHED TABLE IF NOT EXISTS";\r
                }\r
        }\r
-       \r
+\r
        @Override\r
        public <T> void prepareDropView(SQLStatement stat, TableDefinition<T> def) {\r
                StatementBuilder buff = new StatementBuilder("DROP VIEW IF EXISTS "\r
@@ -91,7 +91,8 @@ public class SQLDialectHSQL extends SQLDialectDefault {
                        }\r
                        buff.append(')');\r
                        Object value = def.getValue(obj, field);\r
-                       stat.addParameter(value);\r
+                       Object parameter = serialize(value, field.typeAdapter);\r
+                       stat.addParameter(parameter);\r
                }\r
 \r
                // map to temporary table\r
index 52676d4bb4820d4c20bf0d42bafa92aa1cf913b0..ec5923f6eb7c53bbb3a8a84f35820676809a137d 100644 (file)
@@ -36,7 +36,7 @@ public class SQLDialectMySQL extends SQLDialectDefault {
        protected <T> String prepareCreateTable(TableDefinition<T> def) {\r
                return "CREATE TABLE IF NOT EXISTS";\r
        }\r
-       \r
+\r
        @Override\r
        public <T> void prepareDropView(SQLStatement stat, TableDefinition<T> def) {\r
                StatementBuilder buff = new StatementBuilder("DROP VIEW IF EXISTS "\r
@@ -44,7 +44,7 @@ public class SQLDialectMySQL extends SQLDialectDefault {
                stat.setSQL(buff.toString());\r
                return;\r
        }\r
-       \r
+\r
        @Override\r
        public String prepareColumnName(String name) {\r
                return "`" + name + "`";\r
@@ -77,7 +77,8 @@ public class SQLDialectMySQL extends SQLDialectDefault {
                        buff.appendExceptFirst(", ");\r
                        buff.append('?');\r
                        Object value = def.getValue(obj, field);\r
-                       stat.addParameter(value);\r
+                       Object parameter = serialize(value, field.typeAdapter);\r
+                       stat.addParameter(parameter);\r
                }\r
                buff.append(") ON DUPLICATE KEY UPDATE ");\r
                buff.resetCount();\r
index fc115ab8d604ba4fdc06f57c588e6de1072d7b9d..b5ac5c3a27d1264306de8bf554e72f11e37f1124 100644 (file)
 \r
 package com.iciql;\r
 \r
+import java.sql.SQLException;\r
+\r
+import org.postgresql.util.PGobject;\r
+\r
+import com.iciql.Iciql.DataTypeAdapter;\r
 import com.iciql.TableDefinition.IndexDefinition;\r
 import com.iciql.util.StatementBuilder;\r
 \r
@@ -46,7 +51,7 @@ public class SQLDialectPostgreSQL extends SQLDialectDefault {
 \r
        @Override\r
        protected boolean prepareColumnDefinition(StatementBuilder buff, String dataType,\r
-                       boolean isAutoIncrement, boolean isPrimaryKey) {                \r
+                       boolean isAutoIncrement, boolean isPrimaryKey) {\r
                String convertedType = convertSqlType(dataType);\r
                if (isIntegerType(dataType)) {\r
                        if (isAutoIncrement) {\r
@@ -63,7 +68,7 @@ public class SQLDialectPostgreSQL extends SQLDialectDefault {
                }\r
                return false;\r
        }\r
-       \r
+\r
        @Override\r
        public void prepareCreateIndex(SQLStatement stat, String schemaName, String tableName,\r
                        IndexDefinition index) {\r
@@ -100,4 +105,70 @@ public class SQLDialectPostgreSQL extends SQLDialectDefault {
 \r
                stat.setSQL(buff.toString().trim());\r
        }\r
+\r
+       /**\r
+        * Handles transforming raw strings to/from the Postgres JSON data type.\r
+        */\r
+       public class JsonStringAdapter implements DataTypeAdapter<String> {\r
+\r
+               @Override\r
+               public String getDataType() {\r
+                       return "json";\r
+               }\r
+\r
+               @Override\r
+               public Class<String> getJavaType() {\r
+                       return String.class;\r
+               }\r
+\r
+               @Override\r
+               public Object serialize(String value) {\r
+                       PGobject pg = new PGobject();\r
+                       pg.setType(getDataType());\r
+                       try {\r
+                               pg.setValue(value);\r
+                       } catch (SQLException e) {\r
+                               // not thrown on base PGobject\r
+                       }\r
+                       return pg;\r
+               }\r
+\r
+               @Override\r
+               public String deserialize(Object value) {\r
+                       return value.toString();\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Handles transforming raw strings to/from the Postgres XML data type.\r
+        */\r
+       public class XmlStringAdapter implements DataTypeAdapter<String> {\r
+\r
+               @Override\r
+               public String getDataType() {\r
+                       return "xml";\r
+               }\r
+\r
+               @Override\r
+               public Class<String> getJavaType() {\r
+                       return String.class;\r
+               }\r
+\r
+               @Override\r
+               public Object serialize(String value) {\r
+                       PGobject pg = new PGobject();\r
+                       pg.setType(getDataType());\r
+                       try {\r
+                               pg.setValue(value);\r
+                       } catch (SQLException e) {\r
+                               // not thrown on base PGobject\r
+                       }\r
+                       return pg;\r
+               }\r
+\r
+               @Override\r
+               public String deserialize(Object value) {\r
+                       return value.toString();\r
+               }\r
+       }\r
 }
\ No newline at end of file
index 394fc429c93ed25a73e79ff7ba5a807414dc7979..7eb0b0421da45aef0ccfbeb57bacf2494c1218c6 100644 (file)
@@ -97,7 +97,7 @@ public class SQLStatement {
                                        sb.append('?');\r
                                } else {\r
                                        // static parameter\r
-                                       sb.append(db.getDialect().prepareParameter(o));\r
+                                       sb.append(db.getDialect().prepareStringParameter(o));\r
                                }\r
                                i++;\r
                        }\r
index 0cb1ad27033076509861ee2c287d01ff130762cd..4536695d51479f1ea3455e671574a27644501947 100644 (file)
@@ -33,6 +33,7 @@ import java.util.Set;
 import com.iciql.Iciql.ConstraintDeferrabilityType;\r
 import com.iciql.Iciql.ConstraintDeleteType;\r
 import com.iciql.Iciql.ConstraintUpdateType;\r
+import com.iciql.Iciql.DataTypeAdapter;\r
 import com.iciql.Iciql.EnumId;\r
 import com.iciql.Iciql.EnumType;\r
 import com.iciql.Iciql.IQColumn;\r
@@ -50,6 +51,7 @@ import com.iciql.Iciql.IQTable;
 import com.iciql.Iciql.IQVersion;\r
 import com.iciql.Iciql.IQView;\r
 import com.iciql.Iciql.IndexType;\r
+import com.iciql.Iciql.StandardJDBCTypeAdapter;\r
 import com.iciql.util.IciqlLogger;\r
 import com.iciql.util.StatementBuilder;\r
 import com.iciql.util.StringUtils;\r
@@ -121,6 +123,7 @@ public class TableDefinition<T> {
                Class<?> enumTypeClass;\r
                boolean isPrimitive;\r
                String constraint;\r
+               Class<? extends DataTypeAdapter<?>> typeAdapter;\r
 \r
                Object getValue(Object obj) {\r
                        try {\r
@@ -132,11 +135,11 @@ public class TableDefinition<T> {
 \r
                private Object initWithNewObject(Object obj) {\r
                        Object o = Utils.newObject(field.getType());\r
-                       setValue(obj, o);\r
+                       setValue(null, obj, o);\r
                        return o;\r
                }\r
 \r
-               private void setValue(Object obj, Object o) {\r
+               private void setValue(SQLDialect dialect, Object obj, Object o) {\r
                        try {\r
                                if (!field.isAccessible()) {\r
                                        field.setAccessible(true);\r
@@ -144,6 +147,8 @@ public class TableDefinition<T> {
                                Class<?> targetType = field.getType();\r
                                if (targetType.isEnum()) {\r
                                        o = Utils.convertEnum(o, targetType, enumType);\r
+                               } else if (dialect != null && typeAdapter != null) {\r
+                                       o = dialect.deserialize(o, typeAdapter);\r
                                } else {\r
                                        o = Utils.convert(o, targetType);\r
                                }\r
@@ -407,7 +412,14 @@ public class TableDefinition<T> {
                }\r
        }\r
 \r
-       void mapFields() {\r
+       void defineTypeAdapter(Object column, Class<? extends DataTypeAdapter<?>> typeAdapter) {\r
+               FieldDefinition def = fieldMap.get(column);\r
+               if (def != null) {\r
+                       def.typeAdapter = typeAdapter;\r
+               }\r
+       }\r
+\r
+       void mapFields(Db db) {\r
                boolean byAnnotationsOnly = false;\r
                boolean inheritColumns = false;\r
                if (clazz.isAnnotationPresent(IQTable.class)) {\r
@@ -465,6 +477,9 @@ public class TableDefinition<T> {
                        Class<?> enumTypeClass = null;\r
                        String defaultValue = "";\r
                        String constraint = "";\r
+                       String dataType = null;\r
+                       Class<? extends DataTypeAdapter<?>> typeAdapter = null;\r
+\r
                        // configure Java -> SQL enum mapping\r
                        if (f.getType().isEnum()) {\r
                                enumType = EnumType.DEFAULT_TYPE;\r
@@ -517,6 +532,12 @@ public class TableDefinition<T> {
                                trim = col.trim();\r
                                nullable = col.nullable();\r
 \r
+                               if (col.typeAdapter() != null && col.typeAdapter() != StandardJDBCTypeAdapter.class) {\r
+                                       typeAdapter = col.typeAdapter();\r
+                                       DataTypeAdapter<?> dtt = db.getDialect().getTypeAdapter(col.typeAdapter());\r
+                                       dataType = dtt.getDataType();\r
+                               }\r
+\r
                                // annotation overrides\r
                                if (!StringUtils.isNullOrEmpty(col.defaultValue())) {\r
                                        defaultValue = col.defaultValue();\r
@@ -547,7 +568,8 @@ public class TableDefinition<T> {
                                fieldDef.defaultValue = defaultValue;\r
                                fieldDef.enumType = enumType;\r
                                fieldDef.enumTypeClass = enumTypeClass;\r
-                               fieldDef.dataType = ModelUtils.getDataType(fieldDef);\r
+                               fieldDef.dataType = StringUtils.isNullOrEmpty(dataType) ? ModelUtils.getDataType(fieldDef) : dataType;\r
+                               fieldDef.typeAdapter = typeAdapter;\r
                                fieldDef.constraint = constraint;\r
                                uniqueFields.add(fieldDef);\r
                        }\r
@@ -676,7 +698,8 @@ public class TableDefinition<T> {
                                // try to interpret and instantiate a default value\r
                                value = ModelUtils.getDefaultValue(field, db.getDialect().getDateTimeClass());\r
                        }\r
-                       stat.addParameter(value);\r
+                       Object parameter = db.getDialect().serialize(value, field.typeAdapter);\r
+                       stat.addParameter(parameter);\r
                }\r
                buff.append(')');\r
                stat.setSQL(buff.toString());\r
@@ -711,7 +734,8 @@ public class TableDefinition<T> {
                                // try to interpret and instantiate a default value\r
                                value = ModelUtils.getDefaultValue(field, db.getDialect().getDateTimeClass());\r
                        }\r
-                       stat.addParameter(value);\r
+                       Object parameter = db.getDialect().serialize(value, field.typeAdapter);\r
+                       stat.addParameter(parameter);\r
                }\r
                buff.append(')');\r
                stat.setSQL(buff.toString());\r
@@ -785,7 +809,8 @@ public class TableDefinition<T> {
                                buff.appendExceptFirst(", ");\r
                                buff.append(db.getDialect().prepareColumnName(field.columnName));\r
                                buff.append(" = ?");\r
-                               stat.addParameter(value);\r
+                               Object parameter = db.getDialect().serialize(value, field.typeAdapter);\r
+                               stat.addParameter(parameter);\r
                        }\r
                }\r
                Object alias = Utils.newObject(obj.getClass());\r
@@ -1193,12 +1218,12 @@ public class TableDefinition<T> {
                return columns;\r
        }\r
 \r
-       void readRow(Object item, ResultSet rs, int[] columns) {\r
+       void readRow(SQLDialect dialect, Object item, ResultSet rs, int[] columns) {\r
                for (int i = 0; i < fields.size(); i++) {\r
                        FieldDefinition def = fields.get(i);\r
                        int index = columns[i];\r
                        Object o = def.read(rs, index);\r
-                       def.setValue(item, o);\r
+                       def.setValue(dialect, item, o);\r
                }\r
        }\r
 \r
index b37addb0ce5f48d3c847dfdecce0b078241cb80f..3a00e6dc14592b832fd68e8142ea21539dc972e1 100644 (file)
@@ -26,6 +26,7 @@ This is an overview of the fundamental differences between the original JaQu pro
 <tr><td>DECIMAL(length,scale)</td><td>can specify length/precision and scale</td><td>--</td></tr>\r
 <tr><td>BOOLEAN</td><td>flexible mapping of boolean as bool, varchar, or int</td><td>--</td></tr>\r
 <tr><td>BLOB</td><td>partially supported <em>(can not be used in a WHERE clause)</em></td><td>--</td></tr>\r
+<tr><td>Custom</td><td>partially supported <em>uses custom-defined data type adapter (can not be used in a WHERE clause)</em></td><td>--</td></tr>\r
 <tr><td>UUID</td><td>fully supported <em>(H2 only)</em> </td><td>--</td></tr>\r
 <tr><th colspan="3">configuration</th></tr>\r
 <tr><td>DEFAULT values</td><td>set from annotation, <em>default object values</em>, or Define.defaultValue()</td><td>set from annotations</td></tr>\r
index cb21dcd411465492bcea8416b2851256c678fc80..747c094defd1ff6222f3f9f9e115c00a00bcd50d 100644 (file)
@@ -73,6 +73,8 @@ can be used for all iciql expressions
 can not be directly referenced in an expression</td></tr>\r
 <tr><td>byte []</td> <td></td>\r
 <td>BLOB</td><tr/>\r
+<tr><td>Custom</td> <td>create a DataTypeAdapter&lt;Custom&gt;</td>\r
+<td>Custom</td><tr/>\r
 \r
 <tr><td colspan="3"><b>H2 Database Types</b><br/>\r
 fully supported when paired with an H2 database \r
@@ -180,6 +182,9 @@ public class Product {
        \r
        @IQColumn\r
        private Availability availability;\r
+    \r
+    @IQColumn(typeAdapter = MyCustomClassAdapter.class)\r
+    private MyCustomClass;\r
        \r
        // ignored because it is not annotated AND the class is @IQTable annotated\r
        private Integer ignoredField;\r
diff --git a/src/test/java/com/iciql/test/DataTypeAdapterTest.java b/src/test/java/com/iciql/test/DataTypeAdapterTest.java
new file mode 100644 (file)
index 0000000..f10d298
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2014 James Moger.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.iciql.test;
+
+import java.util.Date;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.iciql.Db;
+import com.iciql.Iciql.IQColumn;
+import com.iciql.Iciql.IQTable;
+import com.iciql.JavaSerializationTypeAdapter;
+import com.iciql.test.models.SupportedTypes;
+
+/**
+ * Tests insertion and retrieval of a custom data type that is automatically transformed
+ * by a Java Object Serialization-based type adapter.
+ */
+public class DataTypeAdapterTest extends Assert {
+
+       private Db db;
+
+
+       @Before
+       public void setUp() {
+               db = IciqlSuite.openNewDb();
+       }
+
+       @After
+       public void tearDown() {
+               db.close();
+       }
+
+       @Test
+       public void testSerializedObjectDataType() {
+
+               SerializedObjectTypeAdapterTest row = new SerializedObjectTypeAdapterTest();
+               row.received = new Date();
+               row.obj = SupportedTypes.createList().get(1);
+               db.insert(row);
+
+               SerializedObjectTypeAdapterTest table = new SerializedObjectTypeAdapterTest();
+               SerializedObjectTypeAdapterTest q1 = db.from(table).selectFirst();
+
+               assertNotNull(q1);
+               assertTrue(row.obj.equivalentTo(q1.obj));
+
+       }
+
+       @IQTable
+       public static class SerializedObjectTypeAdapterTest {
+
+               @IQColumn(autoIncrement = true, primaryKey = true)
+               private long id;
+
+               @IQColumn
+               private java.util.Date received;
+
+               @IQColumn(typeAdapter = SupportedTypesAdapter.class)
+               private SupportedTypes obj;
+
+       }
+
+       /**
+        * Maps a SupportedType instance to a BLOB using Java Object serialization.
+        *
+        */
+       public static class SupportedTypesAdapter extends JavaSerializationTypeAdapter<SupportedTypes> {
+
+               @Override
+               public Class<SupportedTypes> getJavaType() {
+                       return SupportedTypes.class;
+               }
+
+       }
+
+}
index c5d7ce886b4f465ed81f9e43fe2d030eb4308436..3829501e766360565a1f8ad71d6a176c62469f9d 100644 (file)
@@ -48,6 +48,7 @@ import com.beust.jcommander.ParameterException;
 import com.beust.jcommander.Parameters;\r
 import com.iciql.Constants;\r
 import com.iciql.Db;\r
+import com.iciql.test.DataTypeAdapterTest.SerializedObjectTypeAdapterTest;\r
 import com.iciql.test.models.BooleanModel;\r
 import com.iciql.test.models.CategoryAnnotationOnly;\r
 import com.iciql.test.models.ComplexObject;\r
@@ -93,7 +94,8 @@ import com.iciql.util.Utils;
 @SuiteClasses({ AliasMapTest.class, AnnotationsTest.class, BooleanModelTest.class, ClobTest.class,\r
                ConcurrencyTest.class, EnumsTest.class, ModelsTest.class, PrimitivesTest.class, OneOfTest.class,\r
                RuntimeQueryTest.class, SamplesTest.class, UpdateTest.class, UpgradesTest.class, JoinTest.class,\r
-               UUIDTest.class, ViewsTest.class, ForeignKeyTest.class, TransactionTest.class, NestedConditionsTest.class })\r
+               UUIDTest.class, ViewsTest.class, ForeignKeyTest.class, TransactionTest.class, NestedConditionsTest.class,\r
+               DataTypeAdapterTest.class })\r
 public class IciqlSuite {\r
 \r
        private static final TestDb[] TEST_DBS = {\r
@@ -191,6 +193,7 @@ public class IciqlSuite {
                db.dropTable(MultipleBoolsModel.class);\r
                db.dropTable(ProductAnnotationOnlyWithForeignKey.class);\r
                db.dropTable(CategoryAnnotationOnly.class);\r
+               db.dropTable(SerializedObjectTypeAdapterTest.class);\r
 \r
                return db;\r
        }\r
index 9fa4fbc6e4957254322c73c7f76b1762a65883b6..489650e841a7815b38f46b95e0cffca0846387fa 100644 (file)
@@ -17,6 +17,7 @@
 
 package com.iciql.test.models;
 
+import java.io.Serializable;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.text.SimpleDateFormat;
@@ -44,7 +45,9 @@ import com.iciql.util.Utils;
 @IQTable
 @IQIndexes({ @IQIndex({ "myLong", "myInteger" }), @IQIndex(type = IndexType.HASH, value = "myString") })
 @IQVersion(1)
-public class SupportedTypes {
+public class SupportedTypes implements Serializable {
+
+       private static final long serialVersionUID = 1L;
 
        public static final SupportedTypes SAMPLE = new SupportedTypes();