Indicates a persistent entity class. For each entity class, a
PrimaryIndex can be used to store and access instances of that class.
Optionally, one or more
SecondaryIndex objects may be used to access
entity instances by secondary key.
Entity Subclasses and Superclasses
An entity class may have any number of subclasses and superclasses;
however, none of these may themselves be entity classes (annotated with
Entity ).
Entity superclasses are used to share common definitions and instance
data. For example, fields in an entity superclass may be defined as primary
or secondary keys.
Entity subclasses are used to provide polymorphism within a single
PrimaryIndex . Instances of the entity class and its subclasses are stored
in the same
PrimaryIndex . Fields in an entity subclass may be
defined as secondary keys.
For example, the following
BaseClass defines the primary key for
any number of entity classes, using a single sequence to assign primary key
values. The entity class
Pet extends the base class, implicitly
defining a primary index that will contain instances of it and its
subclasses, including
Cat which is defined below. The primary key
(
id ) and secondary key (
name ) can be used to retrieve any
Pet instance.
class BaseClass {
long id;
}
class Pet extends BaseClass {
String name;
float height;
float weight;
}
The entity subclass
Cat defines a secondary key (
finickyness ) that only applies to
Cat instances. Querying by this
key will never retrieve a
Dog instance, if such a subclass existed,
because a
Dog instance will never contain a
finickyness key.
class Cat extends Pet {
int finickyness;
}
Persistent Fields and Types
All non-transient instance fields of an entity class, as well as its
superclasses and subclasses, are persistent.
static and
transient fields are not persistent. The persistent fields of a class may
be
private , package-private (default access),
protected or
public .
It is worthwhile to note the reasons that object persistence is defined
in terms of fields rather than properties (getters and setters). This
allows business methods (getters and setters) to be defined independently of
the persistent state of an object; for example, a setter method may perform
validation that could not be performed if it were called during object
deserialization. Similarly, this allows public methods to evolve somewhat
independently of the (typically non-public) persistent fields.
Simple Types
Persistent types are divided into simple types, enum types, complex
types, and array types. Simple types and enum types are single valued,
while array types may contain multiple elements and complex types may
contain one or more named fields.
Simple types include:
When null values are required (for optional key fields, for example),
primitive wrapper classes must be used instead of primitive types.
Simple types, enum types and array types do not require annotations to
make them persistent.
Complex and Proxy Types
Complex persistent classes must be annotated with
Entity or
Persistent , or must be proxied by a persistent proxy class
(described below). This includes entity classes, subclasses and
superclasses, and all other complex classes referenced via fields of these
classes.
All complex persistent classes must have a default constructor. The
default constructor may be
private , package-private (default
access),
protected , or
public . Other constructors are
allowed but are not used by the persistence mechanism.
It is sometimes desirable to store instances of a type that is externally
defined and cannot be annotated or does not have a default constructor; for
example, a class defined in the Java standard libraries or a 3rd party
library. In this case, a
PersistentProxy class may be used to
represent the stored values for the externally defined type. The proxy
class itself must be annotated with
Persistent like other persistent
classes, and the
Persistent.proxyFor property must be specified.
For convenience, built-in proxy classes are included for several common
classes (listed below) in the Java library. If you wish, you may define
your own
PersistentProxy to override these built-in proxies.
Complex persistent types should in general be application-defined
classes. This gives the application control over the persistent state and
its evolution over time.
Other Type Restrictions
Entity classes and subclasses may not be used in field declarations for
persistent types. Fields of entity classes and subclasses must be simple
types or non-entity persistent types (annotated with
Persistent not
with
Entity ).
Entity classes, subclasses and superclasses may be
abstract and
may implement arbitrary interfaces. Interfaces do not need to be annotated
with
Persistent in order to be used in a persistent class, since
interfaces do not contain instance fields.
Persistent instances of static nested classes are allowed, but the nested
class must be annotated with
Persistent or
Entity . Inner
classes (non-static nested classes, including anonymous classes) are not
currently allowed as persistent types.
Arrays of simple and persistent complex types are allowed as fields of
persistent types. Arrays may be multidimensional. However, an array may
not be stored as a top level instance in a primary index. Only instances of
entity classes and subclasses may be top level instances in a primary
index.
Embedded Objects
As stated above, the embedded (or member) non-transient non-static fields
of an entity class are themselves persistent and are stored along with their
parent entity object. This allows embedded objects to be stored in an
entity to an arbitrary depth.
There is no arbitrary limit to the nesting depth of embedded objects
within an entity; however, there is a practical limit. When an entity is
marshalled, each level of nesting is implemented internally via recursive
method calls. If the nesting depth is large enough, a
StackOverflowError can occur. In practice, this has been observed with a
nesting depth of 12,000, using the default Java stack size.
This restriction on the nesting depth of embedded objects does not apply
to cyclic references, since these are handled specially as described
below.
Object Graphs
When an entity instance is stored, the graph of objects referenced via
its fields is stored and retrieved as a graph. In other words, if a single
instance is referenced by two or more fields when the entity is stored, the
same will be true when the entity is retrieved.
When a reference to a particular object is stored as a member field
inside that object or one of its embedded objects, this is called a cyclic
reference. Because multiple references to a single object are stored as
such, cycles are also represented correctly and do not cause infinite
recursion or infinite processing loops. If an entity containing a cyclic
reference is stored, the cyclic reference will be present when the entity is
retrieved.
Note that the stored object graph is restricted in scope to a single
entity instance. This is because each entity instance is stored separately.
If two entities have a reference to the same object when stored, they will
refer to two separate instances when the entities are retrieved.
See Also: Persistent See Also: PrimaryKey See Also: SecondaryKey See Also: KeyField author: Mark Hayes |