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.ValueSemanticsProviders
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
Colors. 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 UserTypes. 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.