Table of Contents
While Naked Objects supports a similar set of value types to
JPA, it also allows custom value types to be defined
using the @Value
annotation. In addition to the
built-in and custom value types, Naked Objects also has its own set of its
own value types, such as Money
and
Percentage
. These reside in the Naked Objects
applib, in the org.nakedobjects.applib.value
package.
So long as a value type is serializable, then JPA will be able to save the value in the database. However, the value will be stored as a blob, meaning for example it won't be possible to query on it within repositories. And if the value type is not serializable, then JPA will not be able to save it at all.
Hibernate provides a solution to this by allowing us to write (what
it calls) user-defined types, through either the
org.hibernate.usertype.UserType
interface (for
values that are persisted in a single column) or the
org.hiberate.usertype.CompositeUserType
(for more
complex values that are persisted to multiple columns). These are
analogous to the
org.nakedobjects.applib.adapters.ValueSemanticsProvider
s
that accompany Naked Objects' own @Value
annotation: a ValueSemanticsProvider
instructs
Naked Objects viewers how to interact with a custom value, while a
UserType
instructs Hibernate how to
persist/retrieve a value into a database table.
The JPA Objects' Application Library (or
AppLib, see Section 1.1.3, “The JPA Objects AppLib”) defines several
convenience superclasses to help write these
UserType
implementations. There are also
out-of-the-box implementations to support Naked Objects' own value types
(such as org.nakedobjects.applib.value.Money
).
Let's start off with these.
Suppose we want to capture a Person
's
favorite colour, and choose to do this using Naked Objects built-in
org.nakedobjects.applib.value.Color
value
type:
import org.nakedobjects.applib.value.Color; @Entity @DiscriminatorValue("PRS") public class Person { ... public Color getFavoriteColor() { ... } ... }
Only a single column is needed to encode the value, so the
JPA Objects applib provides
org.starobjects.jpa.applib.usertypes.ColorType
, a
UserType
implementation to persist
Color
s. Here's how we use it:
import org.nakedobjects.applib.value.Color; import org.starobjects.jpa.applib.usertypes.ColorType; import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; import org.hibernate.annotations.TypeDefs; ... @Entity @DiscriminatorValue("PRS") @TypeDefs({ @TypeDef(name="nofcolor", typeClass=ColorType.class) }) public class Person { ... @Type(type="nofcolor") public Color getFavoriteColor() { ... } ... }
This sets up the "nofcolor" as an alias to the
ColorType
, and then says to use this alias for
the favoriteColor
property.
We'll have a look at the ColorType
implementation in the below; if you skip ahead you'll see that the value
stored is in fact an integer (corresponding to
Color#intValue()
method and the
#Color(int)
constructor).
Most of the other Naked Objects value types are also mapped using
simple UserType
s. The exception is
Money
, which is mapped as a composite (a string
column for the currency iso code, and a numeric amount). For example, if
there is also a property of type Money
for our
fictitious Person
class, then we would
have:
import org.nakedobjects.applib.value.Money; import org.starobjects.jpa.applib.usertypes.MoneyType; import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; import org.hibernate.annotations.TypeDefs; ... @Entity @DiscriminatorValue("PRS") @TypeDefs({ @TypeDef(name="nofcolor", typeClass=ColorType.class), @TypeDef(name="nofmoney", typeClass=MoneyType.class) }) public class Person { ... @Type(type="nofmoney") public Money getSalary() { ... } ... }
Now we've seen how to use JPA Objects' predefined user types, let's see how to write them for our own value types.