Browse Source

Customizable enumId() mapping (issue 2)

tags/v0.6.0
James Moger 13 years ago
parent
commit
a1ab110531

+ 8
- 2
docs/01_model_classes.mkd View File

<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>

+ 30
- 5
src/com/iciql/Iciql.java View File

* <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;
} }
/** /**

+ 5
- 2
src/com/iciql/IciqlException.java View File

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) {

+ 1
- 0
src/com/iciql/ModelUtils.java View File

} }
return "VARCHAR"; return "VARCHAR";
case ORDINAL: case ORDINAL:
case ENUMID:
return "INT"; return "INT";
} }
} }

+ 15
- 1
src/com/iciql/TableDefinition.java View File

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) {

+ 29
- 16
src/com/iciql/util/Utils.java View File

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);
} }
/** /**

+ 1
- 1
tests/com/iciql/test/ModelsTest.java View File

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

+ 23
- 4
tests/com/iciql/test/models/SupportedTypes.java View File

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;
} }



Loading…
Cancel
Save