<tr><td>byte []</td> | <tr><td>byte []</td> | ||||
<td>BLOB</td></tr> | <td>BLOB</td></tr> | ||||
<tr><td>java.lang.Enum</td> | |||||
<td>VARCHAR/TEXT *@IQEnum(STRING)* or INT *@IQEnum(ORDINAL)*</td></tr> | |||||
<tr><td>java.lang.Enum.name()</td> | |||||
<td>VARCHAR (maxLength > 0) or TEXT (maxLength == 0)<br/>EnumType.STRING</td></tr> | |||||
<tr><td>java.lang.Enum.ordinal()</td> | |||||
<td>INT<br/>EnumType.ORDINAL</td></tr> | |||||
<tr><td>java.lang.Enum implements<br/>*com.iciql.Iciql.EnumId.enumId()*</td> | |||||
<td>INT<br/>EnumType.ENUMID</td></tr> | |||||
</table> | </table> | ||||
* <td>byte []</td> | * <td>byte []</td> | ||||
* <td>BLOB</td> | * <td>BLOB</td> | ||||
* </tr> | * </tr> | ||||
* <tr> | |||||
* <td>java.lang.Enum.name()</td> | |||||
* <td>VARCHAR (maxLength > 0) or TEXT (maxLength == 0)<br/>EnumType.STRING</td> | |||||
* </tr> | |||||
* <tr> | |||||
* <td>java.lang.Enum.ordinal()</td> | |||||
* <td>INT<br/>EnumType.ORDINAL</td> | |||||
* </tr> | |||||
* <tr> | |||||
* <td>java.lang.Enum implements<br/>com.iciql.Iciql.EnumID.enumId()</td> | |||||
* <td>INT<br/>EnumType.ENUMID</td> | |||||
* </tr> | |||||
* </tr> | |||||
* </table> | * </table> | ||||
* <p> | * <p> | ||||
* Unsupported data types: java.lang.Enum, Array Types, and custom types. | |||||
* Unsupported data types: primitives, Array Types, and custom types. | |||||
* <p> | * <p> | ||||
* Table and field mapping: by default, the mapped table name is the class name | * Table and field mapping: by default, the mapped table name is the class name | ||||
* and the public fields are reflectively mapped, by their name, to columns. As | * and the public fields are reflectively mapped, by their name, to columns. As | ||||
} | } | ||||
/** | /** | ||||
* Enumeration representing now to map a java.lang.Enum to a column. | |||||
* Interface for using the EnumType.ENUMID enumeration mapping strategy. | |||||
* <p> | |||||
* Enumerations wishing to use EnumType.ENUMID must implement this | |||||
* interface. | |||||
*/ | |||||
public interface EnumId { | |||||
int enumId(); | |||||
} | |||||
/** | |||||
* Enumeration representing how to map a java.lang.Enum to a column. | |||||
* <p> | * <p> | ||||
* <ul> | * <ul> | ||||
* <li>STRING | |||||
* <li>ORDINAL | |||||
* <li>STRING - name() : string | |||||
* <li>ORDINAL - ordinal() : int | |||||
* <li>ENUMID - enumId() : int | |||||
* </ul> | * </ul> | ||||
* @see com.iciql.Iciql.EnumId interface | |||||
*/ | */ | ||||
public enum EnumType { | public enum EnumType { | ||||
STRING, ORDINAL; | |||||
STRING, ORDINAL, ENUMID; | |||||
} | } | ||||
/** | /** |
package com.iciql; | package com.iciql; | ||||
import java.text.MessageFormat; | |||||
/** | /** | ||||
* Iciql wraps all exceptions with this class. | * Iciql wraps all exceptions with this class. | ||||
*/ | */ | ||||
private static final long serialVersionUID = 1L; | private static final long serialVersionUID = 1L; | ||||
public IciqlException(String message) { | |||||
super(message); | |||||
public IciqlException(String message, Object... parameters) { | |||||
super(parameters.length > 0 ? MessageFormat.format(message, parameters) : message); | |||||
} | } | ||||
public IciqlException(Throwable t) { | public IciqlException(Throwable t) { |
} | } | ||||
return "VARCHAR"; | return "VARCHAR"; | ||||
case ORDINAL: | case ORDINAL: | ||||
case ENUMID: | |||||
return "INT"; | return "INT"; | ||||
} | } | ||||
} | } |
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
import com.iciql.Iciql.EnumId; | |||||
import com.iciql.Iciql.EnumType; | import com.iciql.Iciql.EnumType; | ||||
import com.iciql.Iciql.IQColumn; | import com.iciql.Iciql.IQColumn; | ||||
import com.iciql.Iciql.IQEnum; | import com.iciql.Iciql.IQEnum; | ||||
if (!field.isAccessible()) { | if (!field.isAccessible()) { | ||||
field.setAccessible(true); | field.setAccessible(true); | ||||
} | } | ||||
o = Utils.convert(o, field.getType()); | |||||
Class<?> targetType = field.getType(); | |||||
if (targetType.isEnum()) { | |||||
o = Utils.convertEnum(o, targetType, enumType); | |||||
} else { | |||||
o = Utils.convert(o, targetType); | |||||
} | |||||
field.set(obj, o); | field.set(obj, o); | ||||
} catch (IciqlException e) { | |||||
throw e; | |||||
} catch (Exception e) { | } catch (Exception e) { | ||||
throw new IciqlException(e); | throw new IciqlException(e); | ||||
} | } | ||||
return iqenum.name(); | return iqenum.name(); | ||||
case ORDINAL: | case ORDINAL: | ||||
return iqenum.ordinal(); | return iqenum.ordinal(); | ||||
case ENUMID: | |||||
if (!EnumId.class.isAssignableFrom(value.getClass())) { | |||||
throw new IciqlException(field.field.getName() + " does not implement EnumId!"); | |||||
} | |||||
EnumId enumid = (EnumId) value; | |||||
return enumid.enumId(); | |||||
} | } | ||||
} | } | ||||
if (field.trimString && field.maxLength > 0) { | if (field.trimString && field.maxLength > 0) { |
import java.util.Map; | import java.util.Map; | ||||
import java.util.concurrent.atomic.AtomicLong; | import java.util.concurrent.atomic.AtomicLong; | ||||
import com.iciql.Iciql.EnumId; | |||||
import com.iciql.Iciql.EnumType; | |||||
import com.iciql.IciqlException; | import com.iciql.IciqlException; | ||||
/** | /** | ||||
if (targetType.isAssignableFrom(currentType)) { | if (targetType.isAssignableFrom(currentType)) { | ||||
return o; | return o; | ||||
} | } | ||||
// convert enum | |||||
if (targetType.isEnum()) { | |||||
return convertEnum(o, targetType); | |||||
} | |||||
// convert from CLOB/TEXT/VARCHAR to String | // convert from CLOB/TEXT/VARCHAR to String | ||||
if (targetType == String.class) { | if (targetType == String.class) { | ||||
if (Clob.class.isAssignableFrom(currentType)) { | if (Clob.class.isAssignableFrom(currentType)) { | ||||
} | } | ||||
} | } | ||||
} | } | ||||
throw new IciqlException("Can not convert the value " + o + " from " + currentType + " to " | |||||
+ targetType); | |||||
throw new IciqlException("Can not convert the value {0} from {1} to {2}", o, currentType, targetType); | |||||
} | } | ||||
private static Object convertEnum(Object o, Class<?> targetType) { | |||||
public static Object convertEnum(Object o, Class<?> targetType, EnumType type) { | |||||
if (o == null) { | if (o == null) { | ||||
return null; | return null; | ||||
} | } | ||||
Class<?> currentType = o.getClass(); | Class<?> currentType = o.getClass(); | ||||
if (targetType.isAssignableFrom(currentType)) { | |||||
return o; | |||||
} | |||||
// convert from VARCHAR/TEXT/INT to Enum | // convert from VARCHAR/TEXT/INT to Enum | ||||
Enum<?>[] values = (Enum[]) targetType.getEnumConstants(); | Enum<?>[] values = (Enum[]) targetType.getEnumConstants(); | ||||
if (Clob.class.isAssignableFrom(currentType)) { | if (Clob.class.isAssignableFrom(currentType)) { | ||||
} else if (Number.class.isAssignableFrom(currentType)) { | } else if (Number.class.isAssignableFrom(currentType)) { | ||||
// INT field | // INT field | ||||
int n = ((Number) o).intValue(); | int n = ((Number) o).intValue(); | ||||
// ORDINAL mapping | |||||
for (Enum<?> value : values) { | |||||
if (value.ordinal() == n) { | |||||
return value; | |||||
if (type.equals(EnumType.ORDINAL)) { | |||||
// ORDINAL mapping | |||||
for (Enum<?> value : values) { | |||||
if (value.ordinal() == n) { | |||||
return value; | |||||
} | |||||
} | |||||
} else 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() == n) { | |||||
return value; | |||||
} | |||||
} | } | ||||
} | } | ||||
} | } | ||||
throw new IciqlException("Can not convert the value " + o + " from " + currentType + " to " | |||||
+ targetType); | |||||
throw new IciqlException("Can not convert the value {0} from {1} to {2}", o, currentType, targetType); | |||||
} | } | ||||
/** | /** |
true); | true); | ||||
assertEquals(1, models.size()); | assertEquals(1, models.size()); | ||||
// a poor test, but a start | // a poor test, but a start | ||||
assertEquals(1838, models.get(0).length()); | |||||
assertEquals(1904, models.get(0).length()); | |||||
} | } | ||||
@Test | @Test |
import java.util.List; | import java.util.List; | ||||
import java.util.Random; | import java.util.Random; | ||||
import com.iciql.Iciql.EnumId; | |||||
import com.iciql.Iciql.EnumType; | import com.iciql.Iciql.EnumType; | ||||
import com.iciql.Iciql.IQColumn; | import com.iciql.Iciql.IQColumn; | ||||
import com.iciql.Iciql.IQEnum; | import com.iciql.Iciql.IQEnum; | ||||
} | } | ||||
/** | /** | ||||
* Test of @IQEnum annotated enumeration. | |||||
* This strategy is the default strategy for all fields of the Tree enum. | |||||
* 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 | * Individual Tree field declarations can override this strategy by | ||||
* specifying a different @IQEnum annotation. | * specifying a different @IQEnum annotation. | ||||
* Here ORDINAL specifies that this enum will be mapped to an INT column. | * Here ORDINAL specifies that this enum will be mapped to an INT column. | ||||
*/ | */ | ||||
@IQEnum(EnumType.ORDINAL) | @IQEnum(EnumType.ORDINAL) | ||||
public enum Tree { | |||||
PINE, OAK, BIRCH, WALNUT, MAPLE; | |||||
public enum Tree implements EnumId { | |||||
PINE(10), OAK(20), BIRCH(30), WALNUT(40), MAPLE(50); | |||||
private int enumid; | |||||
Tree(int id) { | |||||
this.enumid = id; | |||||
} | |||||
@Override | |||||
public int enumId() { | |||||
return enumid; | |||||
} | |||||
} | } | ||||
@IQColumn(primaryKey = true, autoIncrement = true) | @IQColumn(primaryKey = true, autoIncrement = true) | ||||
// @IQEnum is set on the enumeration definition and is shared | // @IQEnum is set on the enumeration definition and is shared | ||||
// by all uses of Tree as an @IQColumn | // by all uses of Tree as an @IQColumn | ||||
private Tree myFavoriteTree; | private Tree myFavoriteTree; | ||||
@IQEnum(EnumType.ENUMID) | |||||
@IQColumn | |||||
// override the default enum strategy and use the custom enumid | |||||
private Tree myOtherFavoriteTree; | |||||
public static List<SupportedTypes> createList() { | public static List<SupportedTypes> createList() { | ||||
List<SupportedTypes> list = Utils.newArrayList(); | List<SupportedTypes> list = Utils.newArrayList(); | ||||
s.myFavoriteFlower = Flower.MUM; | s.myFavoriteFlower = Flower.MUM; | ||||
s.myOtherFavoriteFlower = Flower.MARIGOLD; | s.myOtherFavoriteFlower = Flower.MARIGOLD; | ||||
s.myFavoriteTree = Tree.BIRCH; | s.myFavoriteTree = Tree.BIRCH; | ||||
s.myOtherFavoriteTree = Tree.WALNUT; | |||||
return s; | return s; | ||||
} | } | ||||
same &= myFavoriteFlower.equals(s.myFavoriteFlower); | same &= myFavoriteFlower.equals(s.myFavoriteFlower); | ||||
same &= myOtherFavoriteFlower.equals(s.myOtherFavoriteFlower); | same &= myOtherFavoriteFlower.equals(s.myOtherFavoriteFlower); | ||||
same &= myFavoriteTree.equals(s.myFavoriteTree); | same &= myFavoriteTree.equals(s.myFavoriteTree); | ||||
same &= myOtherFavoriteTree.equals(s.myOtherFavoriteTree); | |||||
return same; | return same; | ||||
} | } | ||||