JDO : Persistable Field Types

When persisting a class, a persistence solution needs to know how to persist the types of each field
in the class. Clearly a persistence solution can only support a finite number of Java types; it
cannot know how to persist every possible type creatable. The JDO specification define lists of
types that are required to be supported by all implementations of those specifications.
This support can be conveniently split into two parts

First-Class (FCO) Types

An object that can be referred to (object reference, providing a relation) and that
has an "identity" is termed a First Class Object (FCO). DataNucleus supports the
following Java types as FCO

persistable : any class marked for persistence can be persisted with its own identity in the datastore

interface where the field represents a persistable object

java.lang.Object where the field represents a persistable object

Supported Second-Class (SCO) Types

An object that does not have an "identity" is termed a Second Class Object (SCO).
This is something like a String or Date field in a class, or alternatively a Collection (that
contains other objects). The table below shows the currently supported SCO java types
in DataNucleus. The table shows

Extension? : whether the type is JDO standard, or is a DataNucleus extension

default-fetch-group (DFG) : whether the field is retrieved by default when
retrieving the object itself

persistence-modifier : whether the field is persisted by default, or whether
the user has to mark the field as persistent in XML/annotations to persist it

proxied : whether the field is represented by a "proxy" that intercepts
any operations to detect whether it has changed internally.

primary-key : whether the field can be used as part of the primary-key

Java Type

Extension?

DFG?

Persistent?

Proxied?

PK?

Plugin

boolean

datanucleus-core

byte

datanucleus-core

char

datanucleus-core

double

datanucleus-core

float

datanucleus-core

int

datanucleus-core

long

datanucleus-core

short

datanucleus-core

boolean[]

datanucleus-core

byte[]

datanucleus-core

char[]

datanucleus-core

double[]

datanucleus-core

float[]

datanucleus-core

int[]

datanucleus-core

long[]

datanucleus-core

short[]

datanucleus-core

java.lang.Boolean

datanucleus-core

java.lang.Byte

datanucleus-core

java.lang.Character

datanucleus-core

java.lang.Double

datanucleus-core

java.lang.Float

datanucleus-core

java.lang.Integer

datanucleus-core

java.lang.Long

datanucleus-core

java.lang.Short

datanucleus-core

java.lang.Boolean[]

datanucleus-core

java.lang.Byte[]

datanucleus-core

java.lang.Character[]

datanucleus-core

java.lang.Double[]

datanucleus-core

java.lang.Float[]

datanucleus-core

java.lang.Integer[]

datanucleus-core

java.lang.Long[]

datanucleus-core

java.lang.Short[]

datanucleus-core

java.lang.Number [2]

datanucleus-core

java.lang.Object

datanucleus-core

java.lang.String

datanucleus-core

java.lang.StringBuffer [1]

datanucleus-core

java.lang.String[]

datanucleus-core

java.lang.Class

datanucleus-core

java.math.BigDecimal

datanucleus-core

java.math.BigInteger

datanucleus-core

java.math.BigDecimal[]

datanucleus-core

java.math.BigInteger[]

datanucleus-core

java.sql.Date

datanucleus-core

java.sql.Time

datanucleus-core

java.sql.Timestamp

datanucleus-core

java.util.ArrayList

datanucleus-core

java.util.BitSet

datanucleus-core

java.util.Calendar [5]

datanucleus-core

java.util.Collection

datanucleus-core

java.util.Currency

datanucleus-core

java.util.Date

datanucleus-core

java.util.Date[]

datanucleus-core

java.util.GregorianCalendar [5]

datanucleus-core

java.util.HashMap

datanucleus-core

java.util.HashSet

datanucleus-core

java.util.Hashtable

datanucleus-core

java.util.LinkedHashMap [3]

datanucleus-core

java.util.LinkedHashSet [4]

datanucleus-core

java.util.LinkedList

datanucleus-core

java.util.List

datanucleus-core

java.util.Locale

datanucleus-core

java.util.Locale[]

datanucleus-core

java.util.Map

datanucleus-core

java.util.Properties

datanucleus-core

java.util.PriorityQueue

datanucleus-core

java.util.Queue

datanucleus-core

java.util.Set

datanucleus-core

java.util.SortedMap

datanucleus-core

java.util.SortedSet

datanucleus-core

java.util.Stack

datanucleus-core

java.util.TimeZone

datanucleus-core

java.util.TreeMap

datanucleus-core

java.util.TreeSet

datanucleus-core

java.util.UUID

datanucleus-core

java.util.Vector

datanucleus-core

java.awt.Color

datanucleus-core

java.awt.image.BufferedImage

datanucleus-core

java.awt.Point

datanucleus-geospatial

java.awt.Rectangle

datanucleus-geospatial

java.net.URI

datanucleus-core

java.net.URL

datanucleus-core

java.io.Serializable

datanucleus-core

java.io.File [6]

datanucleus-rdbms

Persistable

datanucleus-core

Persistable[]

datanucleus-core

java.lang.Enum

datanucleus-core

java.lang.Enum[]

datanucleus-core

java.time.LocalDateTime

datanucleus-java8

java.time.LocalTime

datanucleus-java8

java.time.LocalDate

datanucleus-java8

java.time.MonthDay

datanucleus-java8

java.time.YearMonth

datanucleus-java8

java.time.Year

datanucleus-java8

java.time.Period

datanucleus-java8

java.time.Instant

datanucleus-java8

java.time.Duration

datanucleus-java8

java.time.ZoneId

datanucleus-java8

java.time.ZoneOffset

datanucleus-java8

org.joda.time.DateTime

datanucleus-jodatime

org.joda.time.LocalTime

datanucleus-jodatime

org.joda.time.LocalDate

datanucleus-jodatime

org.joda.time.LocalDateTime

datanucleus-jodatime

org.joda.time.Duration

datanucleus-jodatime

org.joda.time.Interval

datanucleus-jodatime

org.joda.time.Period

datanucleus-jodatime

com.google.common.collect.Multiset

datanucleus-guava

[1] - java.lang.StringBuffer dirty check mechanism is limited to immutable mode,
it means, if you change a StringBuffer object field, you must reassign it to the owner object
field to make sure changes are propagated to the database.

[2] - java.lang.Number will be stored in a column capable of storing a
BigDecimal, and will store to the precision of the object to be persisted. On reading back
the object will be returned typically as a BigDecimal since there is no mechanism for
determing the type of the object that was stored.

[3] - java.util.LinkedHashMap treated as a Map currently. No List-ordering is supported.

[4] - java.util.LinkedHashSet treated as a Set currently. No List-ordering is supported.

[5] - java.util.Calendar is, by default, stored in one column (Timestamp - assumes that this stores the TimeZone) but can be stored into
two columns (millisecs, Timezone) if requested.

[6] - available only for RDBMS, persisted into LONGVARBINARY, and retrieved as streamable
so as not to adversely affect memory utilisation, hence suitable for large files.

Note that support is available for persisting other types depending on the datastore to which you are persisting

Handling of second-class types uses wrappers and bytecode enhancement with DataNucleus. This
contrasts to what Hibernate uses (proxies), and what Hibernate imposes on you. See
this blog entry if you
have doubts about this approach.

SortedSet/SortedMap/Queue/PriorityQueue

SortedSet (and implementations) allow the user to have a comparator to order the elements of the set. When an object is pulled back from the datastore
via query JDO would need to know the class name of the comparator to use. You specify it like this

With the default persistence it would persist as String-based, so persisting "RED" "GREEN" "BLUE"
etc. With jdbc-type as INTEGER it would persist 0, 1, 2, 3 being the ordinal values.
If you define the metadata as

this will now persist 1, 3, 5, 8, being the "value" of each of the enum options.

TypeConverters

By default DataNucleus will store the value using its own internal configuration/default
for the java type and for the datastore. The user can, however, change that by making use of a
TypeConverter. You firstly need to define the TypeConverter class (assuming
you aren't going to use an
internal DataNucleus converter,
and for this you should refer to the
TypeConverter plugin-point.
Once you have the converter defined, and registered in a plugin.xml under a name you then
mark the field/property to use it

In this case we have a String field but we want to serialise it, not using normal Java serialisation
but using the "Kryo" library. When it is stored it will be converted into a serialised form
and when read back in will be deserialised. You can see the example Kryo TypeConverter over
on GitHub.

Eclipse EMF models

You could try to persist Eclipse EMF models using
the Texo project to generate POJOs