diff options
author | James Moger <james.moger@gitblit.com> | 2014-10-06 12:46:50 -0400 |
---|---|---|
committer | James Moger <james.moger@gitblit.com> | 2014-10-22 22:29:05 -0400 |
commit | 6889aa2e367d4658105c1bc2514afccb425770f3 (patch) | |
tree | 987102f49e6c6e41facc4dcb7d15db884d49c75b /src/main | |
parent | ecb0c4d4a0f118792c73b1244b389e6a02d00d31 (diff) | |
download | iciql-6889aa2e367d4658105c1bc2514afccb425770f3.tar.gz iciql-6889aa2e367d4658105c1bc2514afccb425770f3.zip |
Support generic types for EnumId mapping
Diffstat (limited to 'src/main')
-rw-r--r-- | src/main/java/com/iciql/Iciql.java | 65 | ||||
-rw-r--r-- | src/main/java/com/iciql/ModelUtils.java | 24 | ||||
-rw-r--r-- | src/main/java/com/iciql/TableDefinition.java | 82 | ||||
-rw-r--r-- | src/main/java/com/iciql/util/Utils.java | 65 |
4 files changed, 144 insertions, 92 deletions
diff --git a/src/main/java/com/iciql/Iciql.java b/src/main/java/com/iciql/Iciql.java index 9f73ffa..521e460 100644 --- a/src/main/java/com/iciql/Iciql.java +++ b/src/main/java/com/iciql/Iciql.java @@ -171,7 +171,7 @@ import java.lang.annotation.Target; * <p>
* Automatic model generation: you may automatically generate model classes as
* strings with the Db and DbInspector objects:
- *
+ *
* <pre>
* Db db = Db.open("jdbc:h2:mem:", "sa", "sa");
* DbInspector inspector = new DbInspector(db);
@@ -179,10 +179,10 @@ import java.lang.annotation.Target; * inspector.generateModel(schema, table, packageName,
* annotateSchema, trimStrings)
* </pre>
- *
+ *
* Or you may use the GenerateModels tool to generate and save your classes to
* the file system:
- *
+ *
* <pre>
* java -jar iciql.jar
* -url "jdbc:h2:mem:"
@@ -190,10 +190,10 @@ import java.lang.annotation.Target; * -package packageName -folder destination
* -annotateSchema false -trimStrings true
* </pre>
- *
+ *
* Model validation: you may validate your model class with DbInspector object.
* The DbInspector will report errors, warnings, and suggestions:
- *
+ *
* <pre>
* Db db = Db.open("jdbc:h2:mem:", "sa", "sa");
* DbInspector inspector = new DbInspector(db);
@@ -208,7 +208,7 @@ public interface Iciql { /**
* An annotation for an iciql version.
* <p>
- *
+ *
* @IQVersion(1)
*/
@Retention(RetentionPolicy.RUNTIME)
@@ -229,7 +229,7 @@ public interface Iciql { /**
* An annotation for a schema.
* <p>
- *
+ *
* @IQSchema("PUBLIC")
*/
@Retention(RetentionPolicy.RUNTIME)
@@ -278,9 +278,9 @@ public interface Iciql { * <li>com.iciql.iciql.IndexType.HASH
* <li>com.iciql.iciql.IndexType.UNIQUE_HASH
* </ul>
- *
+ *
* HASH indexes may only be valid for single column indexes.
- *
+ *
*/
IndexType type() default IndexType.STANDARD;
@@ -307,21 +307,21 @@ public interface Iciql { public static enum ConstraintUpdateType {
UNSET, CASCADE, RESTRICT, SET_NULL, NO_ACTION, SET_DEFAULT;
}
-
+
/**
* Enumeration defining the deferrability.
*/
public static enum ConstraintDeferrabilityType {
UNSET, DEFERRABLE_INITIALLY_DEFERRED, DEFERRABLE_INITIALLY_IMMEDIATE, NOT_DEFERRABLE;
}
-
+
/**
* A foreign key constraint annotation.
* <p>
* <ul>
* <li>@IQContraintForeignKey(
- * foreignColumns = { "idaccount"},
- * referenceName = "account",
+ * foreignColumns = { "idaccount"},
+ * referenceName = "account",
* referenceColumns = { "id" },
* deleteType = ConstrainDeleteType.CASCADE,
* updateType = ConstraintUpdateType.NO_ACTION )
@@ -372,7 +372,7 @@ public interface Iciql { * </ul>
*/
ConstraintDeferrabilityType deferrabilityType() default ConstraintDeferrabilityType.UNSET;
-
+
/**
* The source table for the columns defined as foreign.
*/
@@ -391,7 +391,7 @@ public interface Iciql { * The reference table for the columns defined as references.
*/
String referenceName() default "";
-
+
/**
* Columns defined as 'references'.
* <ul>
@@ -410,7 +410,7 @@ public interface Iciql { public @interface IQContraintsForeignKey {
IQContraintForeignKey[] value() default {};
}
-
+
/**
* A unique constraint annotation.
* <p>
@@ -447,7 +447,7 @@ public interface Iciql { public @interface IQContraintsUnique {
IQContraintUnique[] value() default {};
}
-
+
/**
* Annotation to define a view.
*/
@@ -463,7 +463,7 @@ public interface Iciql { * model class is not annotated with IQView. Default: unspecified.
*/
String name() default "";
-
+
/**
* The source table for the view.
* <p>
@@ -491,7 +491,7 @@ public interface Iciql { */
boolean annotationsOnly() default true;
}
-
+
/**
* String snippet defining SQL constraints for a field. Use "this" as
* a placeholder for the column name. "this" will be substituted at
@@ -507,8 +507,8 @@ public interface Iciql { public @interface IQConstraint {
String value() default "";
- }
-
+ }
+
/**
* Annotation to specify multiple indexes.
*/
@@ -657,7 +657,7 @@ public interface Iciql { */
String defaultValue() default "";
- }
+ }
/**
* Interface for using the EnumType.ENUMID enumeration mapping strategy.
@@ -665,19 +665,22 @@ public interface Iciql { * Enumerations wishing to use EnumType.ENUMID must implement this
* interface.
*/
- public interface EnumId {
- int enumId();
+ public interface EnumId<X> {
+ X enumId();
+ Class<X> enumIdClass();
}
+
+
/**
* Enumeration representing how to map a java.lang.Enum to a column.
* <p>
* <ul>
* <li>NAME - name() : string
* <li>ORDINAL - ordinal() : int
- * <li>ENUMID - enumId() : int
+ * <li>ENUMID - enumId() : X
* </ul>
- *
+ *
* @see com.iciql.Iciql.EnumId interface
*/
public enum EnumType {
@@ -700,14 +703,14 @@ public interface Iciql { * annotation.
* <p>
* The default mapping is by NAME.
- *
+ *
* <pre>
* IQEnum(EnumType.NAME)
* </pre>
- *
+ *
* A string mapping will generate either a VARCHAR, if IQColumn.length > 0
* or a TEXT column if IQColumn.length == 0
- *
+ *
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.TYPE })
@@ -720,9 +723,9 @@ public interface Iciql { */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
- public @interface IQIgnore{
+ public @interface IQIgnore{
}
-
+
/**
* This method is called to let the table define the primary key, indexes,
* and the table name.
diff --git a/src/main/java/com/iciql/ModelUtils.java b/src/main/java/com/iciql/ModelUtils.java index 56e6440..c3fd847 100644 --- a/src/main/java/com/iciql/ModelUtils.java +++ b/src/main/java/com/iciql/ModelUtils.java @@ -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 diff --git a/src/main/java/com/iciql/TableDefinition.java b/src/main/java/com/iciql/TableDefinition.java index e0cc169..0cb1ad2 100644 --- a/src/main/java/com/iciql/TableDefinition.java +++ b/src/main/java/com/iciql/TableDefinition.java @@ -37,11 +37,11 @@ import com.iciql.Iciql.EnumId; import com.iciql.Iciql.EnumType;
import com.iciql.Iciql.IQColumn;
import com.iciql.Iciql.IQConstraint;
+import com.iciql.Iciql.IQContraintForeignKey;
import com.iciql.Iciql.IQContraintUnique;
+import com.iciql.Iciql.IQContraintsForeignKey;
import com.iciql.Iciql.IQContraintsUnique;
import com.iciql.Iciql.IQEnum;
-import com.iciql.Iciql.IQContraintForeignKey;
-import com.iciql.Iciql.IQContraintsForeignKey;
import com.iciql.Iciql.IQIgnore;
import com.iciql.Iciql.IQIndex;
import com.iciql.Iciql.IQIndexes;
@@ -58,7 +58,7 @@ import com.iciql.util.Utils; /**
* A table definition contains the index definitions of a table, the field
* definitions, the table name, and other meta data.
- *
+ *
* @param <T>
* the table type
*/
@@ -79,7 +79,7 @@ public class TableDefinition<T> { /**
* The meta data of a constraint on foreign key.
*/
-
+
public static class ConstraintForeignKeyDefinition {
public String constraintName;
@@ -90,18 +90,18 @@ public class TableDefinition<T> { public ConstraintUpdateType updateType = ConstraintUpdateType.UNSET;
public ConstraintDeferrabilityType deferrabilityType = ConstraintDeferrabilityType.UNSET;
}
-
+
/**
* The meta data of a unique constraint.
*/
-
+
public static class ConstraintUniqueDefinition {
public String constraintName;
public List<String> uniqueColumns;
}
-
-
+
+
/**
* The meta data of a field.
*/
@@ -118,6 +118,7 @@ public class TableDefinition<T> { boolean nullable;
String defaultValue;
EnumType enumType;
+ Class<?> enumTypeClass;
boolean isPrimitive;
String constraint;
@@ -161,12 +162,12 @@ public class TableDefinition<T> { throw new IciqlException(e);
}
}
-
+
@Override
public int hashCode() {
return columnName.hashCode();
}
-
+
@Override
public boolean equals(Object o) {
if (o instanceof FieldDefinition) {
@@ -228,7 +229,7 @@ public class TableDefinition<T> { /**
* Define a primary key by the specified model fields.
- *
+ *
* @param modelFields
* the ordered list of model fields
*/
@@ -239,7 +240,7 @@ public class TableDefinition<T> { /**
* Define a primary key by the specified column names.
- *
+ *
* @param columnNames
* the ordered list of column names
*/
@@ -270,7 +271,7 @@ public class TableDefinition<T> { /**
* Defines an index with the specified model fields.
- *
+ *
* @param name
* the index name (optional)
* @param type
@@ -285,7 +286,7 @@ public class TableDefinition<T> { /**
* Defines an index with the specified column names.
- *
+ *
* @param type
* the index type (STANDARD, HASH, UNIQUE, UNIQUE_HASH)
* @param columnNames
@@ -305,7 +306,7 @@ public class TableDefinition<T> { /**
* Defines an unique constraint with the specified model fields.
- *
+ *
* @param name
* the constraint name (optional)
* @param modelFields
@@ -318,7 +319,7 @@ public class TableDefinition<T> { /**
* Defines an unique constraint.
- *
+ *
* @param name
* @param columnNames
*/
@@ -335,7 +336,7 @@ public class TableDefinition<T> { /**
* Defines a foreign key constraint with the specified model fields.
- *
+ *
* @param name
* the constraint name (optional)
* @param modelFields
@@ -426,7 +427,7 @@ public class TableDefinition<T> { if (inheritColumns) {
Class<?> superClass = clazz.getSuperclass();
classFields.addAll(Arrays.asList(superClass.getDeclaredFields()));
-
+
if (superClass.isAnnotationPresent(IQView.class)) {
IQView superView = superClass.getAnnotation(IQView.class);
if (superView.inheritColumns()) {
@@ -461,6 +462,7 @@ public class TableDefinition<T> { boolean trim = false;
boolean nullable = !f.getType().isPrimitive();
EnumType enumType = null;
+ Class<?> enumTypeClass = null;
String defaultValue = "";
String constraint = "";
// configure Java -> SQL enum mapping
@@ -476,6 +478,11 @@ public class TableDefinition<T> { IQEnum iqenum = f.getAnnotation(IQEnum.class);
enumType = iqenum.value();
}
+
+ if (EnumId.class.isAssignableFrom(f.getType())) {
+ // custom enumid mapping
+ enumTypeClass = ((EnumId<?>) f.getType().getEnumConstants()[0]).enumIdClass();
+ }
}
// try using default object
@@ -515,7 +522,7 @@ public class TableDefinition<T> { defaultValue = col.defaultValue();
}
}
-
+
boolean hasConstraint = f.isAnnotationPresent(IQConstraint.class);
if (hasConstraint) {
IQConstraint con = f.getAnnotation(IQConstraint.class);
@@ -539,13 +546,14 @@ public class TableDefinition<T> { fieldDef.nullable = nullable;
fieldDef.defaultValue = defaultValue;
fieldDef.enumType = enumType;
+ fieldDef.enumTypeClass = enumTypeClass;
fieldDef.dataType = ModelUtils.getDataType(fieldDef);
fieldDef.constraint = constraint;
uniqueFields.add(fieldDef);
}
}
fields.addAll(uniqueFields);
-
+
List<String> primaryKey = Utils.newArrayList();
int primitiveBoolean = 0;
for (FieldDefinition fieldDef : fields) {
@@ -623,7 +631,7 @@ public class TableDefinition<T> { if (!EnumId.class.isAssignableFrom(value.getClass())) {
throw new IciqlException(field.field.getName() + " does not implement EnumId!");
}
- EnumId enumid = (EnumId) value;
+ EnumId<?> enumid = (EnumId<?>) value;
return enumid.enumId();
}
}
@@ -643,7 +651,7 @@ public class TableDefinition<T> { // return the value unchanged
return value;
}
-
+
PreparedStatement createInsertStatement(Db db, Object obj, boolean returnKey) {
SQLStatement stat = new SQLStatement(db);
StatementBuilder buff = new StatementBuilder("INSERT INTO ");
@@ -896,7 +904,7 @@ public class TableDefinition<T> { }
}
}
-
+
// create foreign keys constraints
for (ConstraintForeignKeyDefinition constraint : constraintsForeignKey) {
stat = new SQLStatement(db);
@@ -1004,17 +1012,17 @@ public class TableDefinition<T> { viewTableName = parentView.tableName();
}
}
-
+
if (StringUtils.isNullOrEmpty(viewTableName)) {
// still missing view table name
throw new IciqlException("View model class \"{0}\" is missing a table name!", tableName);
}
}
-
+
// allow control over createTableIfRequired()
createIfRequired = viewAnnotation.create();
}
-
+
if (clazz.isAnnotationPresent(IQIndex.class)) {
// single table index
IQIndex index = clazz.getAnnotation(IQIndex.class);
@@ -1028,7 +1036,7 @@ public class TableDefinition<T> { addIndex(index);
}
}
-
+
if (clazz.isAnnotationPresent(IQContraintUnique.class)) {
// single table unique constraint
IQContraintUnique constraint = clazz.getAnnotation(IQContraintUnique.class);
@@ -1042,7 +1050,7 @@ public class TableDefinition<T> { addConstraintUnique(constraint);
}
}
-
+
if (clazz.isAnnotationPresent(IQContraintForeignKey.class)) {
// single table constraint
IQContraintForeignKey constraint = clazz.getAnnotation(IQContraintForeignKey.class);
@@ -1056,7 +1064,7 @@ public class TableDefinition<T> { addConstraintForeignKey(constraint);
}
}
-
+
}
private void addConstraintForeignKey(IQContraintForeignKey constraint) {
@@ -1064,15 +1072,15 @@ public class TableDefinition<T> { List<String> referenceColumns = Arrays.asList(constraint.referenceColumns());
addConstraintForeignKey(constraint.name(), foreignColumns, constraint.referenceName(), referenceColumns, constraint.deleteType(), constraint.updateType(), constraint.deferrabilityType());
}
-
+
private void addConstraintUnique(IQContraintUnique constraint) {
List<String> uniqueColumns = Arrays.asList(constraint.uniqueColumns());
addConstraintUnique(constraint.name(), uniqueColumns);
}
-
+
/**
* Defines a foreign key constraint with the specified parameters.
- *
+ *
* @param name
* name of the constraint
* @param foreignColumns
@@ -1119,11 +1127,11 @@ public class TableDefinition<T> { List<ConstraintUniqueDefinition> getContraintsUnique() {
return constraintsUnique;
}
-
+
List<ConstraintForeignKeyDefinition> getContraintsForeignKey() {
return constraintsForeignKey;
}
-
+
private void initObject(Object obj, Map<Object, FieldDefinition> map) {
for (FieldDefinition def : fields) {
Object newValue = def.initWithNewObject(obj);
@@ -1152,13 +1160,13 @@ public class TableDefinition<T> { * JaQu assumed that you can always use the integer index of the
* reflectively mapped field definition to determine position in the result
* set.
- *
+ *
* This is not always true.
- *
+ *
* iciql identifies when a select * query is executed and maps column names
* to a column index from the result set. If the select statement is
* explicit, then the standard assumed column index is used instead.
- *
+ *
* @param rs
* @return
*/
diff --git a/src/main/java/com/iciql/util/Utils.java b/src/main/java/com/iciql/util/Utils.java index 64fe6b3..5b2914a 100644 --- a/src/main/java/com/iciql/util/Utils.java +++ b/src/main/java/com/iciql/util/Utils.java @@ -135,8 +135,8 @@ public class Utils { }
}
throw new IciqlException(e,
- "Missing default constructor? Exception trying to instantiate {0}: {1}",
- clazz.getName(), e.getMessage());
+ "Missing default constructor? Exception trying to instantiate {0}: {1}", clazz.getName(),
+ e.getMessage());
}
}
};
@@ -214,8 +214,7 @@ public class Utils { }
}
}
- throw new IciqlException(e,
- "Missing default constructor?! Exception trying to instantiate {0}: {1}",
+ throw new IciqlException(e, "Missing default constructor?! Exception trying to instantiate {0}: {1}",
clazz.getName(), e.getMessage());
}
}
@@ -337,7 +336,7 @@ public class Utils { if (!EnumId.class.isAssignableFrom(o.getClass())) {
throw new IciqlException("Can not convert the enum {0} using ENUMID", o);
}
- EnumId enumid = (EnumId) o;
+ EnumId<?> enumid = (EnumId<?>) o;
return enumid.enumId();
case NAME:
default:
@@ -367,17 +366,39 @@ public class Utils { }
// find name match
- for (Enum<?> value : values) {
- if (value.name().equalsIgnoreCase(name)) {
- return value;
+ if (type.equals(EnumType.ENUMID)) {
+ // ENUMID mapping
+ for (Enum<?> value : values) {
+ EnumId<?> enumid = (EnumId<?>) value;
+ if (enumid.enumId().equals(name)) {
+ return value;
+ }
+ }
+ } else if (type.equals(EnumType.NAME)) {
+ // standard Enum.name() mapping
+ for (Enum<?> value : values) {
+ if (value.name().equalsIgnoreCase(name)) {
+ return value;
+ }
}
}
} else if (String.class.isAssignableFrom(currentType)) {
// VARCHAR field
String name = (String) o;
- for (Enum<?> value : values) {
- if (value.name().equalsIgnoreCase(name)) {
- return value;
+ if (type.equals(EnumType.ENUMID)) {
+ // ENUMID mapping
+ for (Enum<?> value : values) {
+ EnumId<?> enumid = (EnumId<?>) value;
+ if (enumid.enumId().equals(name)) {
+ return value;
+ }
+ }
+ } else if (type.equals(EnumType.NAME)) {
+ // standard Enum.name() mapping
+ for (Enum<?> value : values) {
+ if (value.name().equalsIgnoreCase(name)) {
+ return value;
+ }
}
}
} else if (Number.class.isAssignableFrom(currentType)) {
@@ -397,8 +418,23 @@ public class Utils { }
// ENUMID mapping
for (Enum<?> value : values) {
- EnumId enumid = (EnumId) value;
- if (enumid.enumId() == n) {
+ EnumId<?> enumid = (EnumId<?>) value;
+ if (enumid.enumId().equals(n)) {
+ return value;
+ }
+ }
+ }
+ } else {
+ // custom object mapping
+ if (type.equals(EnumType.ENUMID)) {
+ if (!EnumId.class.isAssignableFrom(targetType)) {
+ throw new IciqlException("Can not convert the value {0} from {1} to {2} using ENUMID", o,
+ currentType, targetType);
+ }
+ // ENUMID mapping
+ for (Enum<?> value : values) {
+ EnumId<?> enumid = (EnumId<?>) value;
+ if (enumid.enumId().equals(o)) {
return value;
}
}
@@ -456,8 +492,7 @@ public class Utils { length = Integer.MAX_VALUE;
}
int block = Math.min(BUFFER_BLOCK_SIZE, length);
- ByteArrayOutputStream out = new ByteArrayOutputStream(length == Integer.MAX_VALUE ? block
- : length);
+ ByteArrayOutputStream out = new ByteArrayOutputStream(length == Integer.MAX_VALUE ? block : length);
byte[] buff = new byte[block];
while (length > 0) {
int len = Math.min(block, length);
|