|
| Note that Cayenne 1.2 supports JDK 1.5 enumerations natively. This example (that infuenced main implementation) applies to JDK 1.4 and/or Cayenne 1.1. |
An implementation of enumerations as ExtendedTypes in Cayenne. Includes support for integer and string based enumerations, which allow you to use strongly typed Java variables backed by constant values to be saved in the database.
Example code can be downloaded from the attachments at the bottom of this page. The [enumerations-source.tar.gz|Enumerations Example^enumerations-source.tar.gz] package contains the required Cayenne source code. The [enumerations-examples-source.tar.gz|Enumerations Example^enumerations-examples-source.tar.gz] package contains examples of two enumerations (integer and string). Lastly, [enumerations-tapestry-source.tar.gz|Enumerations Example^enumerations-tapestry-source.tar.gz] contains an implementation of an IPropertySelectionModel for use in a Tapestry-based application, to enable automatic mapping of Cayenne enumerations to the user-interface pulldowns.
Database Setup
For these examples, the following schema is being used. It contains an integer column (favoriteColor) and a string column (favoriteState) which will get mapped into Cayenne objects as custom enumerations.
mysql> describe UserID; +---------------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------------+-------------+------+-----+---------+-------+ | favoriteColor | int(11) | YES | | NULL | | | primaryKey | int(11) | | PRI | 0 | | | username | varchar(16) | | | | | | favoriteState | char(2) | YES | | NULL | | +---------------+-------------+------+-----+---------+-------+ 4 rows in set (0.09 sec)
Example/Test Datamysql> select * from UserID; +---------------+------------+----------+---------------+ | favoriteColor | primaryKey | username | favoriteState | +---------------+------------+----------+---------------+ | 2 | 260 | mrg | TN | | 3 | 240 | mgentry | VA | | NULL | 220 | admin | NULL | +---------------+------------+----------+---------------+ 3 rows in set (0.06 sec)Cayenne Modeler
The important thing to note with the modeler definition is type specifies the full path to the enumeration. For example, even though favoriteColor maps to an integer in the database, the full class name of the custom enumeration is specified Cayenne Modeler. This will also cause all of the set/get methods in the generated base class to be strongly typed to the custom enumeration.
Modeler Definition<obj-entity name="UserID" className="ct2.UserID" lock-type="optimistic" dbEntityName="UserID"> <obj-attribute name="favoriteColor" type="ct2.ColorEnumeration" lock="true" db-attribute-path="favoriteColor"/> <obj-attribute name="favoriteState" type="ct2.StateEnumeration" lock="true" db-attribute-path="favoriteState"/> <obj-attribute name="username" type="java.lang.String" lock="true" db-attribute-path="username"/> </obj-entity>Color Enumeration
The following code is the example ColorEnumeration, which is an integer-based enumeration. StateEnumeration is very similar, but string-based.
ColorEnumeration.javapackage ct2; import org.objectstyle.cayenne.access.types.IntegerEnumeration; public class ColorEnumeration extends IntegerEnumeration { public static final ColorEnumeration RED = new ColorEnumeration("RED", new Integer(1)); public static final ColorEnumeration GREEN = new ColorEnumeration("GREEN", new Integer(2)); public static final ColorEnumeration BLUE = new ColorEnumeration("BLUE", new Integer(3)); private static ColorEnumeration enumerations[] = {RED, GREEN, BLUE}; private ColorEnumeration(String symbolicName, Integer databaseValue) { super(symbolicName, databaseValue); } public static int numberOfEnumerations() { return numberOfEnumerationsForClass(ColorEnumeration.class); } static { registerEnumerationsForClass(enumerations, ColorEnumeration.class); } }This enumeration creates three constants: RED, GREEN, and BLUE, which can be used by name in your code with the compiler checking the types. These constants have symbolic names (which can be seen when logging SQL) of "RED", "GREEN", and "BLUE" (the names will usually be the same as the constant, but this is not required) and database values of 1, 2, and 3, respectively.
The numberOfEnumerations method is not required, but is an example of a helper method you can create to simplify access to the functions provided by the superclass. There are many functions provided in the superclass which might be good candidates for helper methods.
Lastly, the enumerations must be registered in the superclass. NOTE: Be very careful if copying/pasting from one enumeration class to another to update all of the .class parts to have the correct class name, otherwise the registration/etc will silently fail and cause strange behaviors.
Descriptions
To support locales, the descriptions for the enumerations are kept in a separate Java property file, which is loaded using the ResourceLoader and Locale classes. Refer to the documentation for those classes for the naming schemes used, etc.
ColorEnumeration.propertiesRED = Red GREEN = Green BLUE = BlueYou can create language-specific versions of this file as needed and specify which locale in which you want the description looked up. The left-hand side is the symbolic name (described above) and the right-hand side is the text to display for the enumeration when you ask it for it's description.
Initialization
It is VERY important to initialize your enumerations before you use them, but only do this once.
Configure// Find DataNode DataDomain domain = Configuration.getSharedConfiguration().getDomain(); DataNode node = domain.getNode("UntitledDomainNode"); // Change node name as appropriate // Install ExtendedType (must be done before any enumerations are used) AbstractEnumeration.registerEnumerationsInDataNode(ColorEnumeration.class, node); AbstractEnumeration.registerEnumerationsInDataNode(StateEnumeration.class, node);Inserts, Updates, and Selects
After you have created your enumeration classes, specified them in Cayenne Modeler, and registered them in your DataNode, they can be used as normal objects in Cayenne. The enumeration superclass code handles the translation to the database and back automatically.
Insert (and Update)DataContext dataContext = DataContext.createDataContext(); UserID userID = (UserID) dataContext.createAndRegisterNewObject(UserID.class); userID.setFavoriteColor(ColorEnumeration.GREEN); userID.setFavoriteState(StateEnumeration.TN); userID.setUsername("mrg"); dataContext.commitChanges();Select_expression_ _expression_ = _expression_.fromString("favoriteColor = $color"); Map map = new HashMap(1); map.put("color", ColorEnumeration.GREEN); query = new SelectQuery(UserID.class, _expression_.expWithParameters(map)); list = dataContext.performQuery(query);
