All right, we've created a custom type persistence handler, and it wasn't so bad! Now it's time to actually use it to persist our enumeration data the way we want it.
7.2.1 How do I do that?
This is actually almost embarrassingly easy. Once we've got the value class, SourceMedia , and the persistence manager, SourceMediaType , in place, all we need to do is modify any mapping documents that were previously referring to the raw value type to refer instead to the custom persistence manager.
That's it. No, really!
In our case, that means we change the mapping for the mediaSource property in Track.hbm.xml so it looks like Example 7-2 rather than Example 6-3.
Example 7-2. Custom type mapping for the sourceMedia property
<property name="sourceMedia" type="com.oreilly.hh.SourceMedia Type "> <meta attribute="field-description">Media on which track was obtained</meta> <meta attribute="use-in-tostring">true</meta> </property>
At this point, running ant schema will rebuild the database schema, changing the SOURCEMEDIA column in the TRACK table from integer to VARCHAR (as specified by SourceMediaType 's sqlTypes() method).
Thanks to the beauty of letting the object/relational mapping layer handle the details of how data is stored and retrieved, we don't need to change any aspect of the example or test code that we were using in Chapter 6. You can run ant ctest to create sample data. It will run with no complaint. If you fire up ant db to look at the way it's stored, you'll find that our goal of storing semantically meaningful enumeration symbols has been achieved, as shown in Figure 7-1.
Figure 7-1. Nicer source media information in the TRACK table
Getting the data back out works just as well. Running ant qtest produces output that is identical to what we obtained when we were using Hibernate's built-in, numeric enumeration support. Try it yourself, or compare Example 7-3 with Example 6-5.
Example 7-3. You can't tell the difference at the application layer
... qtest: [java] Track: "Russian Trance" (PPK) 00:03:30, from Compact Disc [java] Track: "Video Killed the Radio Star" (The Buggles) 00:03:49, from VHS Videocassette Tape [java] Track: "Gravity's Angel" (Laurie Anderson) 00:06:06, from Compact Disc [java] Track: "Adagio for Strings (Ferry Corsten Remix)" (Ferry Corsten, William Orbit, Samuel Barber) 00:06:35, from Compact Disc [java] Track: "Test Tone 1" 00:00:10 [java] Comment: Pink noise to test equalization ...
Encapsulation and abstraction are wonderful things, aren't they?
7.2.2 What about...
...More complicated custom type mappings, such as splitting single properties into multiple database columns, or single columns into multiple properties? As noted earlier, your persistence handler class needs to implement CompositeUserType instead of UserType to provide this service. That interface adds only a few more methods for you to flesh out, and they deal primarily with teaching Hibernate about the synthetic properties you want to make available in queries, and providing ways for it to get and set the values of these properties. Let's look at an example!